1. Introduction

This automated reported is intended to serve as a template for a coverage and gaps analyses. It provides examples of the analysis necessary to identify populations in need who are not currently covered by humanitarian action and provide recommendations on how partners may best reach them. Coverage and gaps analyses should be used in tandem with concerted monitoring and evaluation (M&E) – opportunities where Information Management and M&E may reinforce each other are discussed below, in relevant sections.

Coverage and gaps analyses are key documents, but are also rarely taken into account during operational planning or referenced during revisions of major strategic documents, such as Humanitarian Response Plans (HRPs). Neither are they mentioned in OCHA’s HRP guidance.

Given that needs always grossly outweigh available funding, it still remains an industry-wide challenege to respond adequately to gaps in coverage and reallocate resources accordingly. Too often, once committed to a course of action, clusters and their humanitarian partners do not reexamine or reevaluate their interventions. None of the analyses in this document require great skill – they have all been performed by a single analyst; yet, this type of report remains exceedingly rare.

A note on the data

  • Most of the data originates from the Education, Health, Nutrition, Protection and WASH Clusters, from the start of formal 5W data collection to the end of the year 2019 – and any conclusions or analysis are illustrative of only this point in time. Partner data has been anonymised. Other data originate from the census dataset of Venezuela that was maintained by UNICEF. Unlike the document of 5W reporting and cleaning, we will not be exploring the cleaning process. But the source code of each chunk will be displayed when the Code button is clicked.
# reading and cleaning -- you really should break it into parts
ven1 <- read_csv("consolidation 191209 1636.csv") %>% 
  clean_names() %>% 
  # removing unused columns
  select(-c(codigodeestablecimientoocentro, loc_id, hrp_sitre_p_indicator, 
            tipoderespuesta, comentarios, coordeadas_gps_x, coordeadas_gps_y,
            fechade_inicio, fecha_previstade_finalizacion)) %>% 
  # renaming unwieldy columns 
  rename(ubicacion          = comunidadonombredelestablecimiento_centro, 
         sector             = sector_areade_responsabiliad,
         beneficiarios_meta = beneficiarios_meta_numerodepersonas,
         estatus            = estatusdeprogramacion) %>% 
      # mutating the date to the right format
  mutate(month = as.factor(recode(month,
                        `4` = "30/04/2019",
                        `5` = "31/05/2019",
                        `6` = "30/06/2019",
                        `7` = "31/07/2019",
                        `8` = "31/08/2019",
                        `9` = "30/09/2019",
                        `10` = "31/10/2019"))) %>% 
  mutate(month = as.Date(month %>% strptime(., format = "%d/%m/%Y"))) %>% 
  mutate(org_lider = coalesce(org_lider, org_implementadora)) %>% 
  # correcting sector names
  mutate(sector = str_replace_all(sector, c(
    "Agua_saneamiento_higiene"            = "WASH",
    "educacion"                           = "Educacion",
    "Nutricion"                           = "Nutricion",
    "protección_Niños_Niñas_Adolescentes" = "Proteccion_NNA",
    "Protección_Niños_Niñas_Adolescentes" = "Proteccion_NNA",
    "Protección_Violencia_Género"         = "Proteccion_GBV"))) %>% 
  # renaming beneficiary disaggregation columns 
  rename(f_0_18 = f_18,
         m_0_18 = m_18,
         f_18plus = f_18_2,
         m_18plus = m_18_2) %>% 
  mutate(estado    = rm_accent(str_to_upper(estado)), 
         municipio = rm_accent(str_to_upper(municipio)),
         parroquia = rm_accent(str_to_upper(parroquia)),
         ubicacion = rm_accent(str_to_upper(ubicacion)),
         actividad = rm_accent(str_to_upper(actividad)),
         categoria = rm_accent(str_to_upper(categoriadeactividad))) %>% 
  # recoding the estatus column 
  mutate(estatus = str_replace_all(estatus, 
                  c("En ejecucion" = "ejecucion", 
                    "en ejecución" = "ejecucion", 
                    "en Ejecución" = "ejecucion",
                    "En ejecución" = "ejecucion",
                    "En Ejecución" = "ejecucion",
                    "Enejecución"  = "ejecucion",
                    "43741"        = "ejecucion",
                    "finalizada" = "finalizada",
                    "Finalizada" = "finalizada",
                    "Planeada" = "planeada",
                    "planeada con financiamiento" = "planeada",
                    "planeada sin financiamiento" = "planeada"))) %>% 
  replace_na(list(estatus = "ejecucion")) %>% 
  # removing all planned activities 
  filter(estatus != "planeada") %>% 
  filter(str_detect(pcode3, "^VE")) %>% # decide if you want to do this here or later
  select(-c(23:92))

# I'm kinda doubting the use of u_ben, ya I think take it out? since you're only using it once
# Am I just making these out of habit? I could make them inside the 
# code chunk for parr, but maybe I can find some justification for their existence, 
# maybe the disaggregations? 

# Vaccination activities filtered out
u_ben <- ven1 %>% 
  pivot_longer(f_0_18:m_18plus, names_to = "desagregacion", values_to = "beneficiarios") %>% 
  filter(categoriadeactividad != "Vacunacion") %>% 
  filter(beneficiarios != 0) %>% 
  group_by(ubicacion, desagregacion) %>% 
  slice(which.max(beneficiarios)) %>% 
  ungroup()

act_ben <- ven1 %>% 
  pivot_longer(f_0_18:m_18plus, names_to = "desagregacion", values_to = "beneficiarios") %>% 
  filter(beneficiarios != 0) %>% 
  group_by(ubicacion, desagregacion, actividad) %>% 
  slice(which.max(beneficiarios)) %>% 
  ungroup()

# rbind(sum(u_ben$beneficiarios), 
#       sum(act_ben$beneficiarios), 
#       sum(u_ben$beneficiarios) - sum(act_ben$beneficiarios))
# I think this is a gigantic chunk -- cannot decide if I would rather have less things in the 
# environment or if I want more readable chunks. The benefit here I guess is that if I want to change something, I just have to come to this chunk

parr <- u_ben %>% 
  group_by(pcode3) %>% 
  summarise(beneficiarios = sum(beneficiarios)) %>% 
  ungroup() %>% 
  # count of organisations per pcode3
  left_join(act_ben %>% 
             # filter(categoria != "Vacunacion") %>%
             group_by(pcode3) %>% 
             summarise(org_count = n_distinct(org_implementadora))) %>% 
  # getting beneficiary frequencies, sector count and maximum multi-sector beneficiaries
  left_join(act_ben %>%
  # vaccination filtered out  
   filter(categoriadeactividad != "Vacunacion") %>% 
             group_by(ubicacion, desagregacion, sector) %>% 
                 slice(which.max(beneficiarios)) %>% 
                 ungroup() %>%
                 group_by(ubicacion, sector, pcode3) %>% 
                 pivot_wider(names_from = sector, values_from = beneficiarios) %>% 
                 replace_na(list(Nutricion = 0, Educacion = 0, WASH = 0, Salud = 0,
                                 Seguridad_Alimentaria = 0, Proteccion_NNA = 0,
                                 Proteccion_General = 0, Proteccion_GBV = 0)) %>%
             group_by(pcode3, desagregacion) %>% 
             summarise(nutricion_ben   = sum(Nutricion),
                       proteccion_ben  = sum(Proteccion_NNA + Proteccion_General + Proteccion_GBV),
                       wash_ben        = sum(WASH),
                       salud_ben       = sum(Salud),
                       educacion_ben   = sum(Educacion),
                       sa_ben          = sum(Seguridad_Alimentaria), .groups = "drop") %>% 
             mutate(ben_freq   = nutricion_ben + proteccion_ben + wash_ben + salud_ben +
                                 educacion_ben + sa_ben,
                    ben_max    = pmax(nutricion_ben, proteccion_ben, wash_ben, 
                                      salud_ben, educacion_ben, sa_ben),
                    ms_ben_max = ifelse(ben_max >= ben_freq - ben_max, 
                                        ben_freq - ben_max, 
                                        ben_max)) %>% 
             group_by(pcode3) %>% 
             summarise(nutricion_ben  = sum(nutricion_ben),
                       proteccion_ben = sum(proteccion_ben),
                       wash_ben       = sum(wash_ben),
                       salud_ben      = sum(salud_ben),
                       educacion_ben  = sum(educacion_ben),
                       sa_ben         = sum(sa_ben),
                       ben_freq   = sum(ben_freq),
                       ben_max    = sum(ben_max),
                       ms_ben_max = sum(ms_ben_max)) %>% 
             mutate(sector_count = rowSums(select(., ends_with("_ben")) != 0))) %>%  
  filter(str_detect(pcode3, "^VE")) %>% 
  # right_join to the census data
  right_join(read_excel("census data 20191122.xlsx", sheet = "data") %>% 
        clean_names() %>% 
        # selecting variables and renaming them with select
        select(estado, pcode1, municipio, pcode2, parroquia, pcode3, 
               fo = field_office,
               poblacion_2019 = x_2019_poblacion_parroquial_total,
               hogares_2011 = numero_de_hogares, 
               ham_2019_ambitos_ge, 
               percent_pobre = ham_2019_xx_pobreza_env_por_parroquia, 
               pob_pobre = ham_2019_xx_poblacion_pobre_por_parroquia, 
               poblacion_total_2011,
               poblacion_infantil_menor_de_12_anos, poblacion_adolescentes_de_12_a_17_anos,
               poblacion_de_18_anos_y_mas, 
               percent_urbana = poblacion_urbana_percent, 
               area_km2, 
               densidad_ppl_km2 = densidad_poblacional_ppl_km2,
               matricula_2017_educacion_inicial, matricula_2017_educacion_primaria, 
               matricula_2017_educacion_media, razon_de_dependencia_total,
               razon_de_dependencia_de_menores_de_15_anos, 
               percent_sin_agua_segura = x_abast_agua2_percent_sin_agua_segura,
               percent_sin_saneamiento_mejorado =
                 x_saneamiento_percent_sin_saneamiento_mejorado,
               percent_analfabeto = percent_poblacion_10_anos_y_mas_analfabeta,
               promedio_de_personas_por_vivienda,
               percent_hogares_jefatura_femenina = percent_de_hogares_con_jefatura_femenina,
               percent_sin_servicio_electrico =
                 servicio_electrico_percent_no_tiene_servicio_electrico,
               ham_2019_x_violencia_envelope, ham_2019_x_mortalidad_y_salud_envelope, 
               ham_2019_x_pobreza_envelope, promedio_de_edad) %>% 
        mutate(estado     = rm_accent(str_to_upper(estado)), # just to make sure 
               municipio  = rm_accent(str_to_upper(municipio)),
               parroquia  = rm_accent(str_to_upper(parroquia))) %>% 
        # creating new disaggregation variables 
        mutate(pob_menor_de_18 = (poblacion_infantil_menor_de_12_anos +
                                 poblacion_adolescentes_de_12_a_17_anos) /poblacion_total_2011 *
                                 poblacion_2019, 
               pob_18_y_mas    = poblacion_de_18_anos_y_mas / poblacion_total_2011 * poblacion_2019, 
               hogares_2019    = hogares_2011 * poblacion_2019 / poblacion_total_2011, 
               matricula_total = matricula_2017_educacion_inicial + 
                                 matricula_2017_educacion_primaria + 
                                 matricula_2017_educacion_media) %>% 
        # dividing columns by 100 so that they're between 0 and 1
        mutate_at(vars(percent_analfabeto, percent_sin_servicio_electrico, 
                       percent_sin_agua_segura,
                       percent_sin_saneamiento_mejorado,
                       percent_hogares_jefatura_femenina, percent_urbana,
                       razon_de_dependencia_total), ~(. / 100)) %>% 
        # mutating new columns with populations
        mutate(pob_analfabeto               = percent_analfabeto * poblacion_2019,
               pob_sin_agua_segura          = percent_sin_agua_segura * poblacion_2019, 
               pob_sin_servicio_electrico   = percent_sin_servicio_electrico * poblacion_2019,
               pob_sin_saneamiento_mejorado = percent_sin_saneamiento_mejorado * poblacion_2019,
               pob_urbana                   = percent_urbana * poblacion_2019) %>% 
        select(-c(matricula_2017_educacion_inicial, matricula_2017_educacion_primaria, 
               matricula_2017_educacion_media, poblacion_total_2011, hogares_2011,
               poblacion_infantil_menor_de_12_anos, poblacion_adolescentes_de_12_a_17_anos, 
               poblacion_de_18_anos_y_mas)),
            by = "pcode3") %>% 
  # mutating new variables and making sure NAs become 0s 
  mutate(beneficiarios  = ifelse(is.na(beneficiarios), 0, beneficiarios),
         org_count      = ifelse(is.na(org_count), 0, org_count),
         sector_count   = ifelse(is.na(sector_count), 0, sector_count), 
         educacion_ben  = ifelse(is.na(educacion_ben), 0, educacion_ben),
         nutricion_ben  = ifelse(is.na(nutricion_ben), 0, nutricion_ben),
         proteccion_ben = ifelse(is.na(proteccion_ben), 0, proteccion_ben),
         salud_ben      = ifelse(is.na(salud_ben), 0, salud_ben),
         sa_ben         = ifelse(is.na(sa_ben), 0, sa_ben),
         wash_ben       = ifelse(is.na(wash_ben), 0, wash_ben),
         ms_ben_max     = ifelse(is.na(ms_ben_max), 0, ms_ben_max),
         ben_freq       = ifelse(is.na(ben_freq), 0, ben_freq),
         not_reached            = pob_pobre - beneficiarios,
         coverage_percent       = beneficiarios / poblacion_2019,
         coverage_pobre_percent = beneficiarios / pob_pobre,
         percent_total_ben      = beneficiarios / sum(beneficiarios),
         multisector_percent    = ms_ben_max / ben_freq, 
         org_present            = ifelse(beneficiarios > 0, TRUE, FALSE),
         pob_pobre_score     = rescale(pob_pobre, to = c(0,1)), 
         percent_pobre_score = rescale(percent_pobre, to = c(0,1)), 
         poverty_score       = (pob_pobre_score + percent_pobre_score) / 2)

# taking a subset of parr to only get parrishes where the number of beneficiaries does not exceed the number of poor persons

parr0 <- parr %>% 
  filter(not_reached >= 1) %>% 
  mutate(gap_score = (rescale(not_reached, to = c(0,1)) + percent_pobre_score) / 2)

2. Summary of coverage and gaps

2a. Map of parrishes by gaps

# parrishes with negative poor persons are recoded as "0" so they won't mess up the scale
# even though this means that their tooltips are dropped 

gaps_map <- parr %>% 
  right_join(pcode3_shape, by = "pcode3") %>% 
  st_as_sf() %>% 
  mutate(not_reached = ifelse(not_reached < 0.1, 0, not_reached)) %>% 
  mutate(not_reached = round(not_reached, digits = 0)) %>%
  mutate_at(vars(percent_pobre, percent_urbana), ~(round(., digits = 2))) %>% 
  ggplot() +
  geom_sf(aes(fill = not_reached,
              text = paste0(parroquia,",", "\n", 
                           municipio, ",", "\n",
                           estado, "\n", 
                           "not reached: ", not_reached, "\n",
                           "org count: ", org_count, "\n",
                           "poverty incidence: ", percent_pobre, "\n",
                           "percent urban: ", percent_urbana)),
          size = 0.1) +
  scale_fill_viridis_c(option = "turbo", trans = "log10") +
  theme_void() +
  theme(legend.title = element_text(size = 7),
        legend.text = element_text(size = 7),
        plot.title = element_text(size = 10)) +
  labs(fill = "Poor persons \nnot reached") +
  ggtitle("Map of parrishes by gaps in population reached")

# so are you saying that if I change the fill to viridis in the later plot, I can use hoveron = fill?
# no you can't. 
ggplotly(gaps_map, tooltip = c("text")) %>%
  layout(showlegend = TRUE, legend = list(font = list(size = 6))) %>% 
  style(hoveron = "fill") %>% 
  layout(title = list(text = paste0("Map of parrishes by number poor persons not reached",
                                    "<br>",
                                    "<sup>",
                                    "mouse over for details; drag and click to select and zoom; double-click legend select/deselect","</sup>")))

Nationwide, 11,633,901 poor persons have not been reached by response activities – this means that 94.6% all the poor persons in the country have yet to be reached.


2b. Grouping parrishes by coverage

As a starting point, all 1109 parrishes have been split into three groups – over, where the number of unique beneficiaries reached exceeds the number of poor persons in that parrish; under, where the coverage is less than the number of poor persons; and no coverage, comprising a total of 530 parrishes, where no activities have occurred.

However, it should be noted that a total of 11,633,901 poor persons reside in the 530 parrishes that have not been reached, this is only 25% of the 11,170,010 poor persons not covered by response activities. This indicates that 1) there is much room to expand in the parrishes where we are already present and that 2) sparely populated, remote and, consequently, poorer parrishes have, so far, been left out of the response.

parr %>% 
  mutate(coverage_type = case_when(not_reached <= 0 ~ "over",
                                   not_reached > 0 & beneficiarios >= 1 ~ "under", 
                                   beneficiarios == 0 ~ "no_coverage")) %>% 
  group_by(coverage_type) %>% 
  summarise(parroquias = n(),
            beneficiarios = sum(beneficiarios),
            not_reached = sum(not_reached), 
            avg_org_count = mean(org_count),
            percent_pobre = (sum(pob_pobre)) / (sum(poblacion_2019)),
            percent_urbana = (sum(pob_urbana)) / (sum(poblacion_2019)),
            percent_sin_agua_segura = (sum(pob_sin_agua_segura)) / (sum(poblacion_2019)),
            percent_sin_saneamiento_mejorado = (sum(pob_sin_saneamiento_mejorado)) /
              (sum(poblacion_2019)),
            avg_sector_count = mean(sector_count)) %>% 
  gather(key = variable, value = value, 2:ncol(.)) %>% 
  spread_(key = names(.)[1], value = 'value') %>% 
  relocate(no_coverage, .after = under) %>% 
  pander(big.mark = ",")
variable over under no_coverage
avg_org_count 7.818 2.718 0
avg_sector_count 4 1.764 0
beneficiarios 658,812 658,257 0
not_reached -463,891 8,838,144 2,795,757
parroquias 11 568 530
percent_pobre 0.2029 0.3743 0.4602
percent_sin_agua_segura 0.02017 0.1318 0.2304
percent_sin_saneamiento_mejorado 0.01024 0.0697 0.1813
percent_urbana 0.9948 0.9302 0.6795

We note that the 11 parrishes in the over category are much less poor and much more urban despite having 50% of all beneficiaries. These parrishes are shown in the table below. And, as can be seen from not_reached, the number beneficiaries in the over category has greatly exceeded the number of poor persons.


2c. Top parrishes in terms of coverage

Parrishes (admin level 3) will be the main administrative unit of reference. Unlike in the 5W cleaning and reporting document, where we focused on municipalities, greater precision is needed for a coverage and gaps analysis. Furthermore, we should always endeavour to maximise the usage of all available data.

The 11 parrishes below will largely be excluded in the remainder of this report as it is clear that no further resources should be allocated to them:

parr %>% 
  mutate(coverage_type = case_when(not_reached <= 0 ~ "over",
                                   not_reached > 0 & beneficiarios >= 1 ~ "under", 
                                   beneficiarios == 0 ~ "not_reached")) %>%  
  filter(coverage_type == "over") %>% 
  select(estado, municipio, estado, parroquia, beneficiarios, pob_pobre) %>%
  mutate(coverage_percent = beneficiarios / pob_pobre * 100) %>% 
  arrange(desc(beneficiarios)) %>% 
  pander(big.mark = ",")
estado municipio parroquia beneficiarios pob_pobre coverage_percent
DISTRITO CAPITAL LIBERTADOR ALTAGRACIA 321,597 6,244 5,151
MIRANDA SUCRE PETARE 178,814 82,058 217.9
BOLIVAR CARONI ONCE DE ABRIL 69,332 54,118 128.1
BOLIVAR HERES CATEDRAL 32,177 14,336 224.4
BOLIVAR HERES VISTA HERMOSA 18,477 13,919 132.7
MIRANDA CHACAO CHACAO 13,780 5,481 251.4
TACHIRA ANDRES BELLO CAPITAL CORDERO 8,596 7,766 110.7
MIRANDA SUCRE LEONCIO MARTINEZ 6,834 4,792 142.6
CARABOBO VALENCIA URBANA CANDELARIA 5,043 4,589 109.9
TACHIRA BOLIVAR GENERAL JUAN VICENTE GOMEZ 2,253 362.1 622.3
DELTA AMACURO TUCUPITA SAN JOSE 1,909 1,256 152

Though it should be mentioned that it is likely that partners have reported activities which occurred in other parts of the capital in Altagracia, as the total number of benefificaries reached in the whole of Distrito Capital is only # A tibble: 1 x 1, beneficiarios, , 1 415301. It is necessary to check back with partners about this; nevertheless, this is the information we have on hand.


3. Geographical analysis of Gaps

3a. Barplot of coverage and gaps by state

mouse over plot for more details

# ref for printing state_ord. I'm really not sure how to extract all the variables as a list
# parr0 %>% 
#   group_by(estado) %>% 
#   summarise(not_reached = sum(not_reached)) %>% 
#   arrange(desc(not_reached)) %>% 
#   select(estado) %>% as.list(as.data.frame(t(.)))

state_ord <- c("ZULIA", "LARA", "CARABOBO", "MIRANDA", "ANZOATEGUI", "ARAGUA", "BOLIVAR",
               "PORTUGUESA", "SUCRE", "GUARICO", "FALCON", "MONAGAS", "BARINAS", "MERIDA",
               "TACHIRA", "TRUJILLO", "YARACUY", "APURE", "DISTRITO CAPITAL", "NUEVA ESPARTA",
               "COJEDES", "VARGAS", "DELTA AMACURO", "AMAZONAS")
  
stack_text <- parr0 %>% 
  group_by(estado) %>% 
  summarise(beneficiarios = sum(beneficiarios),
            total = sum(pob_pobre)) %>% 
  mutate(percent_reached = round(beneficiarios / total * 100, digits = 2)) %>% 
  arrange(desc(total)) 

state_stack <- parr0 %>% 
  select(estado, beneficiarios, not_reached) %>% 
  group_by(estado) %>%
  summarise(beneficiarios = round(sum(beneficiarios), digits = 0), 
            not_reached = round(sum(not_reached), digits = 0)) %>% 
  pivot_longer(c(beneficiarios,not_reached),
               names_to = "pob_type", values_to = "total") %>% 
  
  ggplot(aes(x = estado, y = total)) +
  geom_col(aes(fill = pob_type)) +
  scale_y_continuous(label = comma) +
  scale_x_discrete(limits = state_ord) +
  scale_fill_manual(values = c("coral", "cornflowerblue")) +
  geom_text(data = stack_text, aes(y = 20000,
                                   label = percent_reached), size = 2) +
  theme(axis.text.x  = element_text(angle = 45, hjust = 1, size = 5),
        axis.text.y  = element_text(size = 5),
        axis.title.y = element_text(size = 8),
        plot.title   = element_text(size = 11)) +
  xlab("") + ylab("Poor persons") + 
  labs(fill = "",
       title = "Barplot of poor persons by state")

ggplotly(state_stack) %>% 
  layout(legend = list(font = list(size = 6))) %>% 
  config(displayModeBar = FALSE)

The states where the highest proportions of poor persons have been reached (listed at the bottom of each bar) are Distrito Capital, Tachira, Bolivar, Delta Amacuro, Miranda and Zulia. Carabobo has the lowest percentage of its poor population covered. On average, after the exclusion of the top 11 parrishes, 10.5% of poor persons have been reached countrywide.

Whilst there are many poor persons yet to be reached in states where we have relatively high coverage, there is a need to ensure that our operational footprint and the consequent resources allocated are equitable – the crisis in Venezuela is nationwide and unlike an earthquake or a typhoon where there is an epicentre or a stormpath, there is no programmatic rationale to only focus on a few areas.

Let us now move down to a lower level of granularity as state-level analysis is still quite superficial:


3b. Scatterplot of gaps by parrish

From the scatterplot below – where each point is a parrish – we see that there is great variation in the number of poor persons not covered (size) as well as how concentrated they are in a given parrish (y-axis, poverty incidence); both these factors weigh heavily in programming strategies as well as in the ease of beneficiary selection.

We also observe that the parrishes with the greatest numbers of not covered (found at poor persons: 10,000-100,000; poverty incidence: 0.25-0.50) have a much higher than average number of organisations present (colour). This means that operational barriers are much lower in accessing these populations than the parrishes in light blue found in the middle of the plot.

parrplot <- parr0 %>% 
  mutate_at(vars(pob_pobre, not_reached, org_count), ~(round(.))) %>% 
  mutate(percent_pobre = round(percent_pobre, digits = 2))%>% 
  ggplot(aes(x = not_reached, y = percent_pobre, 
             colour = org_count, 
             text = paste0(parroquia, ", ", estado))) +
  geom_jitter(aes(size = not_reached), alpha = 0.75) +
  scale_colour_gradientn(
    colours = c("cornflowerblue", "tomato", "firebrick")) +
  scale_x_continuous(trans = "log10", labels = comma) + 
  scale_size_continuous(range = c(0.3, 5)) +
  xlab("Not covered poor") + ylab("Poverty incidence") +
  labs(colour = "Number of \norganisations", 
       title = "Scatterplot of parrishes by poor persons not covered and poverty incidence") +
  theme(legend.title = element_text(size = 7),
        legend.text = element_text(size = 7),
        plot.title = element_text(size = 11),
        axis.title = element_text(size = 8.5))
  

ggplotly(parrplot, tooltip = c("y", "x", "size", "text", "colour")) %>% 
           layout(showlegend = TRUE, legend = list(font = list(size = 7))) %>%
           config(displayModeBar = FALSE) %>% 
  layout(title = list(text = paste0(
    "Scatterplot of parrishes by number poor persons not reached and poverty incidence",
                                    "<br>",
                                    "<sup>",
                                    "size: number of poor persons not reached; colour: number of organisations present; drag and click to select and zoom","</sup>")))


4. Multi-sector programming

Just because two Clusters operate in the same area do not mean their beneficiaries coincide. As an estimate, we calculated a theoretical maximum number of multi-sector beneficiaries per parrish, expressed below as multi_sector_ben (exact calculation and explanation in the code chunk below). Parrishes have then been split into groups based on the number of sectors present within them:

4a. Summary table of multi-sector coverage

# calculation for multi-sector beneficiaries. 
# Basically, beneficiaries per parrish are aggregated into 
# sector subtotals and a beneficiary frequency total.  
# The maximum value of the sector subtotals is compared against the beneficiary frequency total, 
# if the maximum value is equal to the frequency total, then there is only one sector,
# if the maximum value is less than the frequency total, 
# the difference between the two (or the sum of all other sector subtotals) 
# becomes the theoretical maximum number of multisector beneficiaries.

# Performing this calculation at admin level 3 makes sense as a parrish is small enough
# that there it is realistic to assume that overlaps in beneficiaries between sectors exist --
# i.e. that females under 18 in a parrish who are beneficiaries of nutrition 
# and females under 18 in that same parrish who are beneficiaries of WASH are the same people. 

# Although I do feel this calculation to be very charitable 
# We can't really do much more unless there is a beneficiary register. 
# The real number of multisector beneficiaries is likely MUCH LOWER 
# but that can only be verified through sampled large-scale post-distribution/post-intervention monitoring,
# which is extremely rare. 
# I actually could have raised this with the third-party monitors that UNICEF, 
# so it's an oversight on my part as well.

 act_ben %>%
  # vaccination filtered out  
   filter(categoriadeactividad != "Vacunacion") %>% 
             group_by(ubicacion, desagregacion, sector) %>% 
                 slice(which.max(beneficiarios)) %>% 
                 ungroup() %>%
                 group_by(ubicacion, sector, pcode3) %>% 
                 pivot_wider(names_from = sector, values_from = beneficiarios) %>% 
                 replace_na(list(Nutricion = 0, Educacion = 0, WASH = 0, Salud = 0,
                                 Seguridad_Alimentaria = 0, Proteccion_NNA = 0,
                                 Proteccion_General = 0, Proteccion_GBV = 0)) %>%
             group_by(pcode3, desagregacion) %>% 
             summarise(nutricion_ben   = sum(Nutricion),
                       proteccion_ben  = sum(Proteccion_NNA + Proteccion_General + Proteccion_GBV),
                       wash_ben        = sum(WASH),
                       salud_ben       = sum(Salud),
                       educacion_ben   = sum(Educacion),
                       sa_ben          = sum(Seguridad_Alimentaria), .groups = "drop") %>% 
             mutate(ben_freq   = nutricion_ben + proteccion_ben + wash_ben + salud_ben +
                                 educacion_ben + sa_ben,
                    ben_max    = pmax(nutricion_ben, proteccion_ben, wash_ben, 
                                      salud_ben, educacion_ben, sa_ben),
                    ms_ben_max = ifelse(ben_max >= ben_freq - ben_max, 
                                        ben_freq - ben_max, 
                                        ben_max)) %>% 
             group_by(pcode3) %>% 
             summarise(nutricion_ben  = sum(nutricion_ben),
                       proteccion_ben = sum(proteccion_ben),
                       wash_ben       = sum(wash_ben),
                       salud_ben      = sum(salud_ben),
                       educacion_ben  = sum(educacion_ben),
                       sa_ben         = sum(sa_ben),
                       ben_freq   = sum(ben_freq),
                       ben_max    = sum(ben_max),
                       ms_ben_max = sum(ms_ben_max), .groups = "drop") %>% 
             mutate(sector_count = rowSums(select(., ends_with("_ben")) != 0)) %>% 
  group_by(sector_count) %>% 
  # filtering out the parrishes with oversubscription 
  filter(pcode3 %out% c("VE010101", "VE070104", "VE070502", "VE070506", "VE081401", "VE100401",
                        "VE150701", "VE151901", "VE151905", "VE200101", "VE200403")) %>% 
  summarise(parroquias = n(),
            multi_sector_ben = sum(ms_ben_max),
            one_sector_ben = sum(ben_freq) - sum(ms_ben_max), 
            multisector_percent = round(sum(ms_ben_max) / sum(ben_freq) * 100, digits = 2),
            .groups = "drop") %>% 
  relocate(multisector_percent, .after = one_sector_ben) %>% 
  pander()
sector_count parroquias multi_sector_ben one_sector_ben multisector_percent
1 348 0 83,848 0
2 102 16,336 89,572 15.42
3 60 21,887 95,955 18.57
4 40 64,445 153,207 29.61
5 17 34,333 93,604 26.84
6 5 14,072 22,881 38.08

Overall, the results are not encouraging – only 21.9% of all beneficiaries have received multi-sector support. When vaccinations are included, the percentage drops to 8.7%. But we will exclude vaccinations for this analysis as their footprint is determined by government priorities, which may or may not align with the humanitarian imperative; furthermore, the government was not able to provide vaccination records at the parrish level, many times defaulting to municipal or state-level reporting.

As a note number of organisations present in a parrish is highly correlated with the number of sectors present there (a correlation coefficient of 0.913). A scatterplot would be repetitive and very similar to the one in section 3b and not deepen our understanding of the actual coverage.


4b. State-level gaps in multi-sector programming

However, for agencies truly unable to expand outside their current footprints, there are still many beneficiaires who are not covered or have only been reached with the interventions of one sector.

ms_scatter <- parr0 %>% 
  group_by(estado) %>% 
  summarise(multi_sector_ben = sum(ms_ben_max),
            one_sector_ben = round(sum(ben_freq) - sum(ms_ben_max), digits = 0),
            ben_freq = round(sum(ben_freq), digits = 0)) %>% 
  mutate(multisector_percent = round(multi_sector_ben / ben_freq * 100, digits = 1)) %>% 
  ggplot(aes(x = ben_freq, 
             y = multisector_percent)) +
  geom_point(aes(size = one_sector_ben), 
             alpha = 0.8, colour = "coral") +
  geom_text(aes(label = estado), size = 1.5) +
  scale_x_continuous(trans = "log10", labels = comma) +
  scale_size_continuous(range = c(0.3, 10)) +
  xlab("Beneficiary frequencies") + ylab("Percentage received multi-sector support") +
  labs(title = "Scatterplot of states by beneficiary frequencies and multi-sector coverage of beneficiaries")+
  theme(plot.title = element_text(size = 11),
        axis.title = element_text(size = 8.5))

ggplotly(ms_scatter, tooltip = c("x", "y", "text", "size")) %>% 
  layout(legend = list(font = list(size = 6))) %>% 
  config(displayModeBar = FALSE) %>% 
  layout(title = list(text = paste0(
    "Scatterplot of states by beneficiary frequencies and multi-sector coverage of beneficiaries",
                                    "<br>",
                                    "<sup>",
                                    "size: beneficiaries who only received support from one sector; mouse over for details","</sup>")))

As the leader of the Education, Nutrition, WASH and Child Protection Clusters, UNICEF supported activities reaching 95% of all beneficiaries. Meaning that this the low percentage of multi-sector support could be resolved almost entirely by better inter-section coordination and better programmatic oversight within UNICEF. In fact, we note the seeds of this behaviour by the higher rates of multi-sector coverage in the states where UNICEF has offices (Bolivar, Tachira, Zulia and Distrito Capital).

Additionally, 87% of all beneficiaries are from the states of Distrito Capital, Miranda, Tachira, Bolivar and Zulia, indicating that there is significant convergence in the geographical reaches of individual implementing partners.

For those looking for specific parrishes, there is a reference table at the end of this document.


4c. Cluster combinations

Before we examine each cluster in more detail, here is first an overview of the geographic reach of each cluster:

act_ben %>% 
  filter(sector != "Seguridad_Alimentaria" & categoria != "VACUNACION") %>% 
  mutate(sector = ifelse(str_detect(sector, "Proteccion_GBV|Proteccion_General|Proteccion_NNA"), 
                         "Proteccion", sector)) %>% 
  # mutate(sector = ifelse(categoria == "VACUNACION", "Vacunacion", sector))
  # we're not going to look at vaccination in this report 
  group_by(sector) %>% 
  summarise(parrishes = n_distinct(pcode3),
            beneficiary_frequencies = sum(beneficiarios)) %>% 
  rename(cluster = sector) %>% 
  pander(caption = "Cluster summary, vaccination exluded", big.mark = ",", style = "rmarkdown", 
         justify = c("left", "right", "right"))
Cluster summary, vaccination exluded
cluster parrishes beneficiary_frequencies
Educacion 186 624,908
Nutricion 497 352,248
Proteccion 151 183,014
Salud 62 54,800
WASH 126 809,202

The following tables summarise the number of parrishes and beneficiary frequencies reached through the various combinations of different clusters – we use frequencies here, as each individual might have benefitted from multiple combinations of clusters. Each subsection lists the possible pairings of a cluster:

  • combination refers to the various cluster-wise pairs that exist;
  • parrishes indicates the number of parrishes each combination is present in;
  • clust-freq shows the number of beneficiary frequencies reached by that cluster
  • %_subtotal indicates the percentage each combination forms of the subtotal of cluster beneficiary frequencies
  • pair_sum shows the total number of beneficiary frequencies in that pair i.e. the pair_sum for edu_nut would be the sum of education and nutrition beneficiaries.
  • %_ms_max shows the maximum percentage of multisector beneficiaries of each pair i.e. if the pair education-nutrition has 10 education beneficiaries and 30 nutrition beneficiaries, the maximum number of beneficiaries which received support from both sectors is 10, resulting in a %_ms_max of 25%. But, as mentioned in the notes for section 4a, this is a theoretical maximum and the actual level of coincidence is likely much lower.
# creation of reference df for the cluster combinations 
clust_com <- parr %>% 
  filter(ben_freq != 0) %>% 
  select(pcode3, ben_freq, educacion_ben, nutricion_ben, salud_ben, wash_ben, proteccion_ben) %>%
  # mutate a new column for each combination of sectors -- if edu is the first cluster in the combination, 
  # only education beneficiaries will be used to fill values in the column 
  mutate(edu_alone = ifelse(educacion_ben == ben_freq, educacion_ben, 0),
         edu_nut = ifelse(educacion_ben > 0 & nutricion_ben > 0, educacion_ben, 0),
         edu_sal = ifelse(educacion_ben > 0 & salud_ben > 0, educacion_ben, 0),
         edu_wash = ifelse(educacion_ben > 0 & wash_ben > 0, educacion_ben, 0),
         edu_prot = ifelse(educacion_ben > 0 & proteccion_ben > 0, educacion_ben, 0),
         nut_alone = ifelse(nutricion_ben == ben_freq, nutricion_ben, 0),
         nut_edu = ifelse(educacion_ben > 0 & nutricion_ben > 0, nutricion_ben, 0),
         nut_sal = ifelse(nutricion_ben > 0 & salud_ben > 0, nutricion_ben, 0), 
         nut_wash = ifelse(nutricion_ben > 0 & wash_ben > 0, nutricion_ben, 0), 
         nut_prot = ifelse(nutricion_ben > 0 & proteccion_ben > 0, nutricion_ben, 0),
         sal_alone = ifelse(salud_ben == ben_freq, salud_ben, 0),
         sal_edu = ifelse(educacion_ben > 0 & salud_ben > 0, salud_ben, 0),
         sal_nut = ifelse(nutricion_ben > 0 & salud_ben > 0, salud_ben, 0),
         sal_wash = ifelse(salud_ben > 0 & wash_ben > 0, salud_ben, 0),
         sal_prot = ifelse(proteccion_ben > 0 & salud_ben > 0, salud_ben, 0),
         wash_alone = ifelse(wash_ben == ben_freq, wash_ben, 0),
         wash_edu = ifelse(educacion_ben > 0 & wash_ben > 0, wash_ben, 0),
         wash_nut = ifelse(nutricion_ben > 0 & wash_ben > 0, wash_ben, 0),
         wash_sal = ifelse(salud_ben > 0 & wash_ben > 0, wash_ben, 0),
         wash_prot = ifelse(wash_ben > 0 & proteccion_ben > 0, wash_ben, 0),
         prot_alone = ifelse(proteccion_ben == ben_freq, proteccion_ben, 0), 
         prot_edu = ifelse(educacion_ben > 0 & proteccion_ben > 0, proteccion_ben, 0),
         prot_nut = ifelse(nutricion_ben > 0 & proteccion_ben > 0, proteccion_ben, 0),
         prot_sal = ifelse(proteccion_ben > 0 & salud_ben > 0, proteccion_ben, 0),
         prot_wash = ifelse(wash_ben > 0 & proteccion_ben > 0, proteccion_ben, 0)) %>%
  # pivot_longer to the clust_freq column 
  pivot_longer(names_to = "combination", values_to = "clust_freq", 8:32) %>%
  # mutating new cluster column for filtering later
  mutate(cluster = case_when(str_detect(combination, "^edu") ~ "educacion",
                             str_detect(combination, "^nut") ~ "nutricion",
                             str_detect(combination, "^sal") ~ "salud",
                             str_detect(combination, "^wash") ~ "wash",
                             str_detect(combination, "^prot") ~ "proteccion")) %>%
  # calculating the sum of frequencies in each pair
  mutate(pair_freq = 
           case_when(
             str_detect(combination, "edu_nut|nut_edu") ~ educacion_ben + nutricion_ben,
             str_detect(combination, "edu_sal|sal_edu") ~ educacion_ben + salud_ben,
             str_detect(combination, "edu_wash|wash_edu") ~ educacion_ben + wash_ben,
             str_detect(combination, "edu_prot|prot_edu") ~ educacion_ben + proteccion_ben,
             str_detect(combination, "nut_sal|sal_nut") ~ nutricion_ben + salud_ben,
             str_detect(combination, "nut_wash|wash_nut") ~ nutricion_ben + wash_ben,
             str_detect(combination, "nut_prot|prot_nut") ~ nutricion_ben + proteccion_ben,
             str_detect(combination, "sal_wash|wash_sal") ~ salud_ben + wash_ben,
             str_detect(combination, "sal_prot|prot_sal") ~ salud_ben + proteccion_ben,
             str_detect(combination, "prot_wash|wash_prot") ~ proteccion_ben + wash_ben,
             TRUE ~ NA_real_)) %>% 
  mutate(pair_freq = ifelse(str_detect(combination, "alone$"), 0, pair_freq)) %>% 
  select(pcode3, ben_freq, combination, cluster, clust_freq, pair_freq)
clust_com %>% 
  filter(cluster == "educacion" & clust_freq != 0) %>% 
  group_by(combination) %>% 
  summarise(parrishes = n(),
            clust_freq = sum(clust_freq),
            pair_sum = sum(pair_freq)) %>% 
  mutate(ms_max  = round(pmin(clust_freq, abs(clust_freq - pair_sum)), digits = 1),
         `%_ms_max` = round(ms_max / pair_sum * 100, digits = 1),
         `%_ms_max` = ifelse(is.infinite(`%_ms_max`), 0, `%_ms_max`)) %>% 

  pander(caption = "Education cluster combinations", big.mark = ",", style = "rmarkdown", 
         justify = c("left", "right", "right", "right", "right", "right"))
Education cluster combinations
combination parrishes clust_freq pair_sum ms_max %_ms_max
edu_alone 33 26,570 0 26,570 0
edu_nut 132 241,390 306,424 65,034 21.2
edu_prot 81 183,820 296,182 112,362 37.9
edu_sal 38 82,489 116,730 34,241 29.3
edu_wash 83 204,964 911,894 204,964 22.5

The most common pairing for Education was with the Nutrition cluster – they coincide in 132 parrishes. However, there are no concrete programmatic links programmatically between the two, with Nutrition focusing on persons older or younger than the majority of Education’s beneficiaries. However, Protection and WASH both have explicit programmatic links (in the logframe) with Education and 81 and 83 parrishes respectively. A fruitful avenue of investigation would be how many beneficiaries of Education also benefitted from Protection interventions and how close it is to the 37.9% theoretical maximum.


clust_com %>% 
  filter(cluster == "nutricion" & clust_freq != 0) %>% 
  group_by(combination) %>% 
  summarise(parrishes = n(),
            clust_freq = sum(clust_freq),
            pair_sum = sum(pair_freq)) %>% 
  mutate(`%_subtotal` = round(clust_freq / sum(clust_freq) * 100, digits = 1),
         `%_ms_max` = round(pmin(clust_freq, abs(clust_freq - pair_sum)) / pair_sum * 100, digits = 1),
         `%_ms_max` = ifelse(is.infinite(`%_ms_max`), 0, `%_ms_max`)) %>% 
    relocate(`%_subtotal`, .after = clust_freq) %>% 

  pander(caption = "Nutrition cluster combinations", big.mark = ",", style = "rmarkdown", 
         justify = c("left", "right", "right", "right", "right", "right"))
Nutrition cluster combinations
combination parrishes clust_freq %_subtotal pair_sum %_ms_max
nut_alone 282 48,576 19.3 0 0
nut_edu 132 65,034 25.9 306,424 21.2
nut_prot 125 57,871 23 203,461 28.4
nut_sal 48 25,875 10.3 62,717 41.3
nut_wash 97 53,753 21.4 758,861 7.1

Nutrition operates alone in 282 parrishes out of the 497 that it operates in, this is the most out of any of the other clusters – it is necessary to evaluate the extent to which other clusters can make use of the footholds established by Nutrition. In this light, it seems that its high level of coincidence with Education was due more to its wide operational presence rather than due to concerted coordination. The highest possibility of overlap is with Health, due to 1) their respective beneficiary frequencies not differing as much as with the other clusters and 2) the numerous programmatic links between the two. However, has the lowest number of beneficiaries in parrishes wherre health is also present.


clust_com %>% 
  filter(cluster == "salud" & clust_freq != 0) %>% 
  group_by(combination) %>% 
  summarise(parrishes = n(),
            clust_freq = sum(clust_freq),
            pair_sum = sum(pair_freq)) %>% 
  mutate(`%_subtotal` = round(clust_freq / sum(clust_freq) * 100, digits = 1),
         `%_ms_max` = round(pmin(clust_freq, abs(clust_freq - pair_sum)) / pair_sum * 100, digits = 1),
         `%_ms_max` = ifelse(is.infinite(`%_ms_max`), 0, `%_ms_max`)) %>% 
    relocate(`%_subtotal`, .after = clust_freq) %>% 

  pander(caption = "Health cluster combinations, excluding vaccinations", 
         big.mark = ",", style = "rmarkdown", 
         justify = c("left", "right", "right", "right", "right", "right"))
Health cluster combinations, excluding vaccinations
combination parrishes clust_freq %_subtotal pair_sum %_ms_max
sal_alone 3 142 0.1 0 0
sal_edu 38 34,241 24.8 116,730 29.3
sal_nut 48 36,842 26.7 62,717 41.3
sal_prot 34 34,339 24.9 85,516 40.2
sal_wash 32 32,372 23.5 331,648 9.8

Without vaccination interventions, health has the smallest footprint of any of the clusters, covering 62 parrishes and 54800 beneficiary frequencies. It coincides the most with Nutrition and Protection and has numerous programmatic opportunities to coordinate with both at the intervention level with its focus on obstetric, antenatal and neonatal care as well as with HIV diagnosis and treatment.


clust_com %>% 
  filter(cluster == "wash" & clust_freq != 0) %>% 
  group_by(combination) %>% 
  summarise(parrishes = n(),
            clust_freq = sum(clust_freq),
            pair_sum = sum(pair_freq)) %>% 
  mutate(`%_subtotal` = round(clust_freq / sum(clust_freq) * 100, digits = 1),
         `%_ms_max` = round(pmin(clust_freq, abs(clust_freq - pair_sum)) / pair_sum * 100, digits = 1),
         `%_ms_max` = ifelse(is.infinite(`%_ms_max`), 0, `%_ms_max`)) %>% 
    relocate(`%_subtotal`, .after = clust_freq) %>% 

  pander(caption = "WASH cluster combinations", big.mark = ",", style = "rmarkdown", 
         justify = c("left", "right", "right", "right", "right", "right"))
WASH cluster combinations
combination parrishes clust_freq %_subtotal pair_sum %_ms_max
wash_alone 12 5,663 0.2 0 0
wash_edu 83 706,930 29.4 911,894 22.5
wash_nut 97 705,108 29.3 758,861 7.1
wash_prot 67 689,628 28.7 798,852 13.7
wash_sal 32 299,276 12.4 331,648 9.8

Almost none of WASH’s beneficiary frequencies occurred in parrishes where no other clusters were present. Its great reach and blanket coverage (especially water supply and other community-level activities) mean that other clusters operating in the same areas as WASH are “guaranteed” to reach beneficiaries with multi-sector programming – the challenges being 1. the intentionality of the multi-sector coverage and 2. matching the scale of WASH activities. WASH has excellent programmatic overlap with all other clusters.


clust_com %>% 
  filter(cluster == "proteccion" & clust_freq != 0) %>% 
  group_by(combination) %>% 
  summarise(parrishes = n(),
            clust_freq = sum(clust_freq),
            pair_sum = sum(pair_freq)) %>% 
  mutate(`%_subtotal` = round(clust_freq / sum(clust_freq) * 100, digits = 1),
         `%_ms_max` = round(pmin(clust_freq, abs(clust_freq - pair_sum)) / pair_sum * 100, digits = 1),
         `%_ms_max` = ifelse(is.infinite(`%_ms_max`), 0, `%_ms_max`)) %>% 
    relocate(`%_subtotal`, .after = clust_freq) %>% 

  pander(caption = "Protection cluster combinations", big.mark = ",", style = "rmarkdown", 
         justify = c("left", "right", "right", "right", "right", "right"))
Protection cluster combinations
combination parrishes clust_freq %_subtotal pair_sum %_ms_max
prot_alone 15 2,796 0.7 0 0
prot_edu 81 112,362 26.7 296,182 37.9
prot_nut 125 145,590 34.6 203,461 28.4
prot_sal 34 51,177 12.2 85,516 40.2
prot_wash 67 109,224 25.9 798,852 13.7

Like WASH and health, Protection has very limited beneficiary frequencies in parrishes where it operates alone. Protection coincides the most with Nutrition – this should serve as an impulse for the creation of referral pathways between the two since both carry out screening activities; additionally, both manage some form of beneficiary-level database. This cluster has the most explicit progammatic links to Education.

To close, the state of multi-sector programming is poor. There is little intentionality in which areas have multi-sector coverage and which areas do not – multi-sector links do exist at the activity level, but this is a poor approximation of developing a programme based on the specific needs of a target area. We see much better multi-sector coverage in the areas where UNICEF has offices, indicating that field offices should be afforded greater primacy in dictating cluster footprints in their respective areas.


5. Decision trees

5a. Introduction to trees – orgasational presence

To aid prioritisation of parrishes – that is, to determine where we should be working – it is necessary to split them up into more easily digestible groups – we will use decision trees to do this. A prioritisation score is also another commonly-used prioritisation tool, but, as we will see, collapsing a number of variables down into one score is not always helpful.

To understand how a decision tree functions, let us construct one to predict whether or not there is a humanitarian agency present in a parrish (org_present – this is our dependent variable). We supply the model our basket of indicators from which it will construct a model to predict our dependent variable – unhide the code below to see the full model – but we mostly fed the model the Census indicators. The decision tree printed below is the result:

# just to show the decision tree of how partners seem to have chosen locations. 
# using full parr dataset for the tree
# no doubt there are other factors, but this is the data I have -- 
# looking at specific partner characteristics would be interesting. 
set.seed(3000)

tree2 <- parr %>% 
  rpart(org_present ~ percent_pobre + percent_urbana + densidad_ppl_km2 + 
        razon_de_dependencia_de_menores_de_15_anos + razon_de_dependencia_total +  
        percent_sin_agua_segura + percent_sin_saneamiento_mejorado +
        percent_sin_servicio_electrico + percent_analfabeto + percent_hogares_jefatura_femenina, 
        promedio_de_personas_por_vivienda, data = ., minbucket = 100)

fancyRpartPlot(tree2, digits = -3, sub = "", palettes = "Blues", type = 2)

To understand the plot above, all parrishes have been split into four groups (the terminal nodes at the bottom marked 4, 5, 6 and 7) based on the percentage of parrishes in each node where humanitarian agencies are present. Each bubble has three figures – for instance, the root, at the top, and marked [1], shows that on average, 0.524 or 52.4% of all parrishes have humanitarian agencies present in them. The next numbers, “n = 1109” shows that 1109 parrishes are in that group and next to it is the percentage of parrishes it contains, which, since it is the root, is 100%.

We see that 7 (in dark blue) the node with the highest concentration of parrishes with agencies present (82.8%), consists of parrishes more than 79.4% urbanised and denser than 187 ppl/km2. And 4, the node with the lowest concentration of parrishes with agencies (22.6%) is less than 79.4% urbanised and less than 21.8% urbanised.

Perhaps it is understandable that the most heavily populated parrishes have greater concentrations of organisations, though population density and urban population are both negatively correlated with poverty incidence. And this is, of course, not to imply that this actually depicts partners’ decision-making process, just that these are the factors towards which we, as a response, are predisposed.

The largest determinants of the number of beneficiaries reached per parrish are population density and percentage urban, as beneficiary numbers tend to scale in line with larger populations.


5b. Prioritisation trees

Several trees were built and trialled to split parrishes into targetting groups. As mentioned, the independent variables come from a pool of indicators from the census dataset, with some originating from the 2019 UNICEF Municipal Prioritisation Tool, which was a Principal Components Analysis of key variables related to poverty, health and mortality and violence and insecurity. After numerous iterations, tree3 was chosen and it splits parrishes into groups according to the:

  • The poverty score, which is the a rescaled average of the number of poor persons and the poverty incidence of each parrish.

To see the specific variables and formulae used for each of the major iterations, as well as additional notes on the development and application of decision trees, unhide the source code below.

# As opposed to a prioritisation score -- typically the weighted average of several demographic and socioeconomic indicators -- a tree is much better at accounting for the variations across geographic areas. A partner might not have the capacity to work outside of urban areas or another might have specific geographic biases and decision trees are a good tool to make the best possible targetting decisions within one's constraints.  

# With that in mind, tree3 was developed to aid future prioritisation. The independent variable it strives to predict is the poverty score, which, as mentioned, is just the rescaled average of number of poor persons and poverty incidence. The performance of tree3 was considered superior to both tree1 (whose indendepent variable is just the absolute number of poor persons) and tree4 due to its ability clearly distinguish its groups of parrishes and because it is not dependent on gaps data -- meaning it will not shift when the 5Ws are updated.

set.seed(3000)

# number of not covered poor persons 
tree1 <- parr0 %>%
  rpart(not_reached ~ estado + percent_pobre + percent_urbana + 
        densidad_ppl_km2 + razon_de_dependencia_de_menores_de_15_anos + 
        razon_de_dependencia_total +  
        percent_sin_agua_segura + percent_sin_saneamiento_mejorado +
        percent_sin_servicio_electrico + percent_analfabeto + percent_hogares_jefatura_femenina, 
        promedio_de_personas_por_vivienda, data = ., cp = 0.038)

# tree based on poverty_score
tree3 <- parr0 %>%
  rpart(poverty_score ~ estado + percent_urbana + densidad_ppl_km2 +
        razon_de_dependencia_de_menores_de_15_anos + razon_de_dependencia_total +  
        percent_sin_agua_segura + percent_sin_saneamiento_mejorado +
        percent_sin_servicio_electrico + percent_analfabeto + percent_hogares_jefatura_femenina,
        promedio_de_personas_por_vivienda, data = ., cp = 0.044)

# tree based on gap score -- let's not use this as tree3 is more stable and will not change based on new 5W data 
# tree4 <- parr0 %>%
#   rpart(gap_score ~ estado + percent_urbana + densidad_ppl_km2 +
#         razon_de_dependencia_de_menores_de_15_anos + razon_de_dependencia_total +  
#         percent_sin_agua_segura + percent_sin_saneamiento_mejorado +
#         percent_sin_servicio_electrico + percent_analfabeto + percent_hogares_jefatura_femenina, 
#         promedio_de_personas_por_vivienda, data = ., cp = 0.045)

# plotcp(tree3)
# printcp(tree3)

# adding tree1 and tree3 rules to the dataset 
parr0 <- parr0 %>% 
  mutate(rule1 = row.names(tree1$frame)[tree1$where]) %>%
      left_join(rpart.rules.table(tree1) %>% 
      filter(Leaf == TRUE) %>% 
      rename(rule1 = Rule) %>% 
      group_by(rule1) %>% 
      summarise(subrules1 = paste(Subrule, collapse = ",")))  %>% 
  mutate(rule3 = row.names(tree3$frame)[tree3$where]) %>%
      left_join(rpart.rules.table(tree3) %>% 
      filter(Leaf == TRUE) %>% 
      rename(rule3 = Rule) %>% 
      group_by(rule3) %>% 
      summarise(subrules3 = paste(Subrule, collapse = ",")))


5c. Sub-groups of decision tree3

Below is a plot of tree3 – the 1098 parrishes where the number of beneficiaries does not exceed the number of poor persons (corresponding to the under and no coverage categories) have been split into four terminal nodes: 4, 5, 6 and 7. The manner in which they have been split is meaningful for targetting decisions and this section will compare the characteristics of each.

fancyRpartPlot(tree3, digits = -3, sub = "", palettes = "Blues", type = 2)


Summary table of the terminal nodes of tree3

parr0 %>% 
  group_by(rule3) %>% 
  summarise(parr_no_ben = n_distinct(pcode3[beneficiarios == 0]),
            beneficiarios = sum(beneficiarios),
            avg_beneficiarios = sum(beneficiarios) / n(), 
            not_reached = sum(not_reached),
            avg_not_reached = sum(not_reached) / n(),
            avg_org_count = mean(org_count),
            avg_poblacion = mean(poblacion_2019),
            percent_pobre = round(sum(pob_pobre) / sum(poblacion_2019), digits = 2),
            percent_urbana = round(sum(pob_urbana) / sum(poblacion_2019), digits = 2),
            densidad_ppl_km2 = sum(poblacion_2019) / sum(area_km2, na.rm = TRUE),
            parroquias = n()) %>% 
  gather(key = variable, value = value, 2:ncol(.)) %>% 
  spread_(key = names(.)[1], value = 'value') %>% 
  # reordering the table instead of having it be alphabetical
  arrange(factor(variable, levels = c("not_reached", "avg_not_reached", "avg_poblacion", 
                                      "beneficiarios",
                                      "avg_beneficiarios",  "avg_org_count",
                                      "percent_pobre", "percent_urbana", "densidad_ppl_km2", 
                                      "parroquias", "parr_no_ben"))) %>%  
  
  pander(big.mark = ",")
variable 4 5 6 7
not_reached 1,091,079 6,371,849 3,648,710 522,263
avg_not_reached 8,659 12,898 9,653 5,223
avg_poblacion 46,126 35,806 19,120 7,174
beneficiarios 176,330 352,663 111,813 17,452
avg_beneficiarios 1,399 713.9 295.8 174.5
avg_org_count 2.508 1.666 0.9683 0.39
percent_pobre 0.22 0.38 0.52 0.75
percent_urbana 0.99 0.93 0.75 0.23
densidad_ppl_km2 996.1 147.4 18.07 1.855
parroquias 126 494 378 100
parr_no_ben 38 211 205 76
  • 4 consists of population centres which are easy to reach, but with only 21.8% of the population being poor, careful targetting and beneficiary selection is required – blanket coverage will only result in excessive inclusion errors. It also has the highest average number of organisations present per parrish (avg_org_count). There are 126 parrishes in this group. These parrishes should not be prioritised – resources should be allocated elsewhere.

  • 5 is probably the best option for expansion for most partners – it has the highest concentration of poor persons not covered per parrish (nc_per_parr), is substantially poorer than 4, with a poverty incidence of 38%. Additionally, these parrishes are still very urbanised (92.5%), meaning that access to these populations will not be challenging. The coverage of organisations is still fairly high and partners should consider expanding into parrishes to the ones they currently cover. This is the largest group, with 494 parrishes.

  • 6 is where access starts to get more challenging – though these parrishes have an average poverty incidence of 52%, the rate of urbanisation drops to 75% and the population density is only 18 ppl/km2. But there are still more poor persons not covered per parrish in this group than in 4. There are 378 parrishes in this group.

  • 7 consists of the poorest, most vulnerable and most remote parrishes. Working in these areas will incur significant operational and logistical costs. However, with an average poverty incidence of 75.2%, blanket coverage will be warranted in many cases – if the challenge of reaching all of the population can be met. Additionally, they also have the lowest average number of poor persons not covered, given their extremely low population density of 1.8 ppl/km2. Humanitarian agencies have the lowest presence in these parrishes. It is advisable for donors to incentivise activities in these areas as it is clear that humanitarian agencies are avoiding them. There are 100 parrishes in this group.

5d. Maps of parrishes by decision tree node

# just one note for this map -- I still can't figure out how to get the tooltip to appear when
# you're hovering over the centroid instead of at the border; hoveron fill doesn't work. 
# I think you should just ask stackoverflow GIS

# hex for Set2 "#66C2A5", "#FC8D62", "#8DA0CB", "#E78AC3", "#FFFFFF"
# hex for Dark2 "#1B9E77", "#D95F02", "#7570B3", "#E7298A", "#FFFFFF"
# hex for Accent "#7FC97F", "#BEAED4", "#FDC086", "#FFFF99", "#FFFFFF"
# scale_fill_viridis_d()
# scale_fill_manual(values = c())

parrmap_org <- parr %>% 
  left_join(parr0 %>% 
              select(pcode3, rule3), by = "pcode3") %>% 
  right_join(pcode3_shape, by = "pcode3") %>% 
  st_as_sf() %>% 
  mutate(not_reached = round(not_reached, digits = 0),
         tree_node = rule3) %>% 
  mutate_at(vars(percent_pobre, percent_urbana), ~(round(., digits = 2))) %>% 
  ggplot() +
  geom_sf(size = 0.1, 
          aes(fill = tree_node,
              text = paste0(parroquia,",", "\n", 
                           municipio, ",", "\n",
                           estado, "\n", 
                           "not covered: ", not_reached, "\n",
                           "poverty incidence: ", percent_pobre, "\n",
                           "percent urban: ", percent_urbana, "\n",
                           "org present :", org_present),
             alpha = org_present)) +
  theme_void() +
  scale_fill_manual(values = c("#66C2A5", "#FC8D62", "#8DA0CB", "#E78AC3")) +
  scale_alpha_discrete(range = c(1, 0.7)) +
  theme(legend.title = element_text(size = 7),
        legend.text = element_text(size = 7),
        plot.title = element_text(size = 11)) +
  guides(alpha = FALSE) +
  labs(fill = "Tree node",
       alpha = "") +
  ggtitle('Map of parrishes by decision tree node (colour) & if organisations present (alpha)')
  
ggplotly(parrmap_org, tooltip = c("text", "fill")) %>%
  layout(title = list(text = paste0(
    "Map of parrishes by decision tree node (colour) & if organisations present (alpha)",
                                    "<br>",
                                    "<sup>",
                                     "mouse over for details; drag and click to select and zoom; double-click legend select/deselect","</sup>")))

Above is a map of parrishes by their decision tree node (denoted by colour), we have also decreased the alpha for parrishes where there are already organisations present, meaning that they appear more transparent. Looking at 4 and 5, we can see the parrishes that conform to the the Venezuela Costal Range and the Venezuelan Andes, where most of the country’s population is concentrated; as a reminder, parrishes in node 5 are excellent candidates for expansion.

We also see three large clusters of parrishes from node 7 – the poorest and most-sparsely populated areas – in Amazonas and Bolivar (at the bottom of the map), in Delta Amacuro (at the extreme right) and in Lara and Falcon (top-left).

  • Additional notes on tree1, which was not selected – unhide code to see
# the main problem I see is that each of the leaves has little variance in terms of poverty incidence
# but let me know if you want maps or products focused on this tree, it's pretty easy to do. [15] is very, very attractive. Maybe I can 

# 6 is dense, urban and highest operational presence,
# 2 is just too big. 800 parrishes is just too many. The low end is distinguished much better in tree3
# 14 is just rich, urban and not a priority. It's also a really small leaf.  
# 15 is actually a really good leaf -- really high nc_per_parr, few parrishes, very dense, very urban and 42% poor and such an immensely low coverage percent. Good low-hanging fruit. I almost want to keep tree1 just because of this leaf. Maybe I will make one map just for this. 59,508 nc_per_parr is massive. 

parr0 %>% 
  group_by(rule1) %>% 
  summarise(parr_no_ben = n_distinct(pcode3[beneficiarios == 0]), 
            beneficiarios = sum(beneficiarios),
            ben_per_parr = sum(beneficiarios) / n(), 
            not_reached = sum(not_reached),
            nr_per_parr = sum(not_reached) / n(),
            nc_per_mun = sum(not_reached) / n_distinct(pcode2), 
            avg_org_count = mean(org_count),
            coverage_percent = sum(beneficiarios) / sum(poblacion_2019),
            percent_pobre = sum(pob_pobre) / sum(poblacion_2019),
            percent_urbana = sum(pob_urbana) / sum(poblacion_2019),
            densidad_ppl_km2 = sum(poblacion_2019) / sum(area_km2, na.rm = TRUE),
            parroquias = n(),
            municipios = n_distinct(pcode2),
            parr_per_mun = n() / n_distinct(pcode2)) %>% 
  gather(key = variable, value = value, 2:ncol(.)) %>% 
  spread_(key = names(.)[1], value = 'value') %>% 
  arrange(factor(variable, levels = c("not_reached", "nr_per_parr", "nc_per_mun", "beneficiarios",
                                      "ben_per_parr",  "avg_org_count", "coverage_percent",
                                      "percent_pobre", "percent_urbana", "densidad_ppl_km2", 
                                      "parroquias", "parr_no_ben", "municipios", 
                                      "parr_per_mun"))) %>%  pander(big.mark = ",")



6. Reference Table

type or use slider to filter by categories or values

parr0 %>%
  select(-percent_total_ben) %>% 
  mutate(sector_count = rowSums(select(., ends_with("_ben"))!=0)) %>% 
  mutate(educacion_only = ifelse(educacion_ben > 0, "educacion", ""),
         nutricion_only = ifelse(nutricion_ben > 0, "nutricion", ""),
         salud_only = ifelse(salud_ben > 0, "salud",  ""),
         wash_only = ifelse(wash_ben > 0, "wash", ""),
         proteccion_only = ifelse(proteccion_ben > 0, "proteccion", ""),
         sectors_present = str_trim(paste0(educacion_only, " ", nutricion_only, " ", proteccion_only, " ", 
                                  salud_only, " ", wash_only))) %>% 
  mutate_at(vars(pob_pobre, not_reached, org_count), ~(round(., digits = 0))) %>% 
  mutate_at(vars(percent_pobre, percent_urbana), ~(round(., digits = 2))) %>% 
  select(estado, municipio, parroquia,  
         percent_pobre, percent_urbana, not_reached, beneficiarios, tree_node = rule3,
         org_count, sector_count, sectors_present, pcode3) %>% 
  arrange(desc(not_reached)) %>% 
  # the js is adjusting the font size for the whole container -- there doesn't seem to be another way
  datatable(filter = "top", options = list(pageLength = 10, scrollX = TRUE,
                                           initComplete = htmlwidgets::JS(
          "function(settings, json) {",
          paste0("$(this.api().table().container()).css({'font-size': '", "8.5pt", "'});"),
          "}")
       ) 
     ) 
LS0tDQp0aXRsZTogIkNvdmVyYWdlIGFuZCBnYXBzIGluIHRoZSBodW1hbml0YXJpYW4gcmVzcG9uc2UgaW4gVmVuZXp1ZWxhIGluIDIwMTkiDQphdXRob3I6ICJTZWFuIE5nIg0KZGF0ZTogIjI1LzExLzIwMjEiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICB0aGVtZTogcmVhZGFibGUNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQogICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgIA0KLS0tDQoNCjxzdHlsZT4NCiAgICBib2R5IC5tYWluLWNvbnRhaW5lciB7DQogICAgICAgIG1heC13aWR0aDogMTI4MHB4Ow0KICAgIH0NCjwvc3R5bGU+DQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcud2lkdGg9OC41LCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmc9RkFMU0UpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KHN0cmluZ2kpDQpsaWJyYXJ5KHN0cmluZ3IpDQoNCmxpYnJhcnkocGFuZGVyKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGthYmxlRXh0cmEpDQoNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGdnZm9yY2UpDQpsaWJyYXJ5KGdncHVicikNCmxpYnJhcnkoZm9yY2F0cykNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KDQpsaWJyYXJ5KHJhdHRsZSkNCmxpYnJhcnkocnBhcnQpDQpsaWJyYXJ5KHJwYXJ0LnBsb3QpDQpsaWJyYXJ5KHJwYXJ0LnV0aWxzKQ0KbGlicmFyeShwYXJ0eWtpdCkNCmxpYnJhcnkoY29ycnBsb3QpDQpsaWJyYXJ5KGZhY3RvZXh0cmEpDQpsaWJyYXJ5KHNoaW55KQ0KDQpsaWJyYXJ5KGdnbWFwKQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeShzZikNCmxpYnJhcnkocm1hcHNoYXBlcikNCmxpYnJhcnkodmlyaWRpcykNCg0KIyBkaXNhYmxpbmcgc2NpZW50aWZpYyBub3RhdGlvbg0Kb3B0aW9ucyhzY2lwZW4gPSAxMDApDQoNCiMgcGFuZGVyIHRhYmxlcyBhbGwgaW4gb25lIHJvdw0KcGFuZGVyT3B0aW9ucygndGFibGUuc3BsaXQudGFibGUnLCBJbmYpDQoNCiMgcGFuZGVyIHRob3VzYW5kcyBzZXBhcmF0b3INCnBhbmRlck9wdGlvbnMoImJpZy5tYXJrIiwgIiwiKQ0KDQpgJW91dCVgIDwtIE5lZ2F0ZShgJWluJWApDQoNCiMgZnVuY3Rpb24gdG8gcmVtb3ZlIGFjY2VudHMgDQpybV9hY2NlbnQgPC0gZnVuY3Rpb24oY29sbnMpew0KICBjb2xucyA8LSBzdHJpX3RyYW5zX2dlbmVyYWwoY29sbnMsICJMYXRpbi1BU0NJSSIpDQp9DQoNCmBgYA0KDQojIyAxLiBJbnRyb2R1Y3Rpb24NCg0KVGhpcyBhdXRvbWF0ZWQgcmVwb3J0ZWQgaXMgaW50ZW5kZWQgdG8gc2VydmUgYXMgYSB0ZW1wbGF0ZSBmb3IgYSBjb3ZlcmFnZSBhbmQgZ2FwcyBhbmFseXNlcy4gSXQgcHJvdmlkZXMgZXhhbXBsZXMgb2YgdGhlIGFuYWx5c2lzIG5lY2Vzc2FyeSB0byBpZGVudGlmeSBwb3B1bGF0aW9ucyBpbiBuZWVkIHdobyBhcmUgbm90IGN1cnJlbnRseSBjb3ZlcmVkIGJ5IGh1bWFuaXRhcmlhbiBhY3Rpb24gYW5kIHByb3ZpZGUgcmVjb21tZW5kYXRpb25zIG9uIGhvdyBwYXJ0bmVycyBtYXkgYmVzdCByZWFjaCB0aGVtLiBDb3ZlcmFnZSBhbmQgZ2FwcyBhbmFseXNlcyBzaG91bGQgYmUgdXNlZCBpbiB0YW5kZW0gd2l0aCBjb25jZXJ0ZWQgbW9uaXRvcmluZyBhbmQgZXZhbHVhdGlvbiAoTSZFKSAtLSBvcHBvcnR1bml0aWVzIHdoZXJlIEluZm9ybWF0aW9uIE1hbmFnZW1lbnQgYW5kIE0mRSBtYXkgcmVpbmZvcmNlIGVhY2ggb3RoZXIgYXJlIGRpc2N1c3NlZCBiZWxvdywgaW4gcmVsZXZhbnQgc2VjdGlvbnMuIA0KDQpDb3ZlcmFnZSBhbmQgZ2FwcyBhbmFseXNlcyBhcmUga2V5IGRvY3VtZW50cywgYnV0IGFyZSBhbHNvIHJhcmVseSB0YWtlbiBpbnRvIGFjY291bnQgZHVyaW5nIG9wZXJhdGlvbmFsIHBsYW5uaW5nIG9yIHJlZmVyZW5jZWQgZHVyaW5nIHJldmlzaW9ucyBvZiBtYWpvciBzdHJhdGVnaWMgZG9jdW1lbnRzLCBzdWNoIGFzIEh1bWFuaXRhcmlhbiBSZXNwb25zZSBQbGFucyAoSFJQcykuIE5laXRoZXIgYXJlIHRoZXkgbWVudGlvbmVkIGluIE9DSEEncyBIUlAgZ3VpZGFuY2UuIA0KDQpHaXZlbiB0aGF0IG5lZWRzIGFsd2F5cyBncm9zc2x5IG91dHdlaWdoIGF2YWlsYWJsZSBmdW5kaW5nLCBpdCBzdGlsbCByZW1haW5zIGFuIGluZHVzdHJ5LXdpZGUgY2hhbGxlbmVnZSB0byByZXNwb25kIGFkZXF1YXRlbHkgdG8gZ2FwcyBpbiBjb3ZlcmFnZSBhbmQgcmVhbGxvY2F0ZSByZXNvdXJjZXMgYWNjb3JkaW5nbHkuIFRvbyBvZnRlbiwgb25jZSBjb21taXR0ZWQgdG8gYSBjb3Vyc2Ugb2YgYWN0aW9uLCBjbHVzdGVycyBhbmQgdGhlaXIgaHVtYW5pdGFyaWFuIHBhcnRuZXJzIGRvIG5vdCByZWV4YW1pbmUgb3IgcmVldmFsdWF0ZSB0aGVpciBpbnRlcnZlbnRpb25zLiBOb25lIG9mIHRoZSBhbmFseXNlcyBpbiB0aGlzIGRvY3VtZW50IHJlcXVpcmUgZ3JlYXQgc2tpbGwgLS0gdGhleSBoYXZlIGFsbCBiZWVuIHBlcmZvcm1lZCBieSBhIHNpbmdsZSBhbmFseXN0OyB5ZXQsIHRoaXMgdHlwZSBvZiByZXBvcnQgcmVtYWlucyBleGNlZWRpbmdseSByYXJlLiANCg0KDQojIyMjIEEgbm90ZSBvbiB0aGUgZGF0YQ0KDQoqIE1vc3Qgb2YgdGhlIGRhdGEgb3JpZ2luYXRlcyBmcm9tIHRoZSBFZHVjYXRpb24sIEhlYWx0aCwgTnV0cml0aW9uLCBQcm90ZWN0aW9uIGFuZCBXQVNIIENsdXN0ZXJzLCBmcm9tIHRoZSBzdGFydCBvZiBmb3JtYWwgNVcgZGF0YSBjb2xsZWN0aW9uIHRvIHRoZSBlbmQgb2YgdGhlIHllYXIgMjAxOSAtLSBhbmQgYW55IGNvbmNsdXNpb25zIG9yIGFuYWx5c2lzIGFyZSBpbGx1c3RyYXRpdmUgb2Ygb25seSB0aGlzIHBvaW50IGluIHRpbWUuIFBhcnRuZXIgZGF0YSBoYXMgYmVlbiBhbm9ueW1pc2VkLiBPdGhlciBkYXRhIG9yaWdpbmF0ZSBmcm9tIHRoZSBjZW5zdXMgZGF0YXNldCBvZiBWZW5lenVlbGEgdGhhdCB3YXMgbWFpbnRhaW5lZCBieSBVTklDRUYuIFVubGlrZSB0aGUgZG9jdW1lbnQgb2YgNVcgcmVwb3J0aW5nIGFuZCBjbGVhbmluZywgd2Ugd2lsbCBub3QgYmUgZXhwbG9yaW5nIHRoZSBjbGVhbmluZyBwcm9jZXNzLiBCdXQgdGhlIHNvdXJjZSBjb2RlIG9mIGVhY2ggY2h1bmsgd2lsbCBiZSBkaXNwbGF5ZWQgd2hlbiB0aGUgYENvZGVgIGJ1dHRvbiBpcyBjbGlja2VkLiANCg0KYGBge3IgcmVhZGluZy1hbmQtY2xlYW5pbmctYW5kLWludGVybWVkaXRlLW91cHV0c30NCg0KIyByZWFkaW5nIGFuZCBjbGVhbmluZyAtLSB5b3UgcmVhbGx5IHNob3VsZCBicmVhayBpdCBpbnRvIHBhcnRzDQp2ZW4xIDwtIHJlYWRfY3N2KCJjb25zb2xpZGF0aW9uIDE5MTIwOSAxNjM2LmNzdiIpICU+JSANCiAgY2xlYW5fbmFtZXMoKSAlPiUgDQogICMgcmVtb3ZpbmcgdW51c2VkIGNvbHVtbnMNCiAgc2VsZWN0KC1jKGNvZGlnb2RlZXN0YWJsZWNpbWllbnRvb2NlbnRybywgbG9jX2lkLCBocnBfc2l0cmVfcF9pbmRpY2F0b3IsIA0KICAgICAgICAgICAgdGlwb2RlcmVzcHVlc3RhLCBjb21lbnRhcmlvcywgY29vcmRlYWRhc19ncHNfeCwgY29vcmRlYWRhc19ncHNfeSwNCiAgICAgICAgICAgIGZlY2hhZGVfaW5pY2lvLCBmZWNoYV9wcmV2aXN0YWRlX2ZpbmFsaXphY2lvbikpICU+JSANCiAgIyByZW5hbWluZyB1bndpZWxkeSBjb2x1bW5zIA0KICByZW5hbWUodWJpY2FjaW9uICAgICAgICAgID0gY29tdW5pZGFkb25vbWJyZWRlbGVzdGFibGVjaW1pZW50b19jZW50cm8sIA0KICAgICAgICAgc2VjdG9yICAgICAgICAgICAgID0gc2VjdG9yX2FyZWFkZV9yZXNwb25zYWJpbGlhZCwNCiAgICAgICAgIGJlbmVmaWNpYXJpb3NfbWV0YSA9IGJlbmVmaWNpYXJpb3NfbWV0YV9udW1lcm9kZXBlcnNvbmFzLA0KICAgICAgICAgZXN0YXR1cyAgICAgICAgICAgID0gZXN0YXR1c2RlcHJvZ3JhbWFjaW9uKSAlPiUgDQogICAgICAjIG11dGF0aW5nIHRoZSBkYXRlIHRvIHRoZSByaWdodCBmb3JtYXQNCiAgbXV0YXRlKG1vbnRoID0gYXMuZmFjdG9yKHJlY29kZShtb250aCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGA0YCA9ICIzMC8wNC8yMDE5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGA1YCA9ICIzMS8wNS8yMDE5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGA2YCA9ICIzMC8wNi8yMDE5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGA3YCA9ICIzMS8wNy8yMDE5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGA4YCA9ICIzMS8wOC8yMDE5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGA5YCA9ICIzMC8wOS8yMDE5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGAxMGAgPSAiMzEvMTAvMjAxOSIpKSkgJT4lIA0KICBtdXRhdGUobW9udGggPSBhcy5EYXRlKG1vbnRoICU+JSBzdHJwdGltZSguLCBmb3JtYXQgPSAiJWQvJW0vJVkiKSkpICU+JSANCiAgbXV0YXRlKG9yZ19saWRlciA9IGNvYWxlc2NlKG9yZ19saWRlciwgb3JnX2ltcGxlbWVudGFkb3JhKSkgJT4lIA0KICAjIGNvcnJlY3Rpbmcgc2VjdG9yIG5hbWVzDQogIG11dGF0ZShzZWN0b3IgPSBzdHJfcmVwbGFjZV9hbGwoc2VjdG9yLCBjKA0KICAgICJBZ3VhX3NhbmVhbWllbnRvX2hpZ2llbmUiICAgICAgICAgICAgPSAiV0FTSCIsDQogICAgImVkdWNhY2lvbiIgICAgICAgICAgICAgICAgICAgICAgICAgICA9ICJFZHVjYWNpb24iLA0KICAgICJOdXRyaWNpb24iICAgICAgICAgICAgICAgICAgICAgICAgICAgPSAiTnV0cmljaW9uIiwNCiAgICAicHJvdGVjY2nDs25fTmnDsW9zX05pw7Fhc19BZG9sZXNjZW50ZXMiID0gIlByb3RlY2Npb25fTk5BIiwNCiAgICAiUHJvdGVjY2nDs25fTmnDsW9zX05pw7Fhc19BZG9sZXNjZW50ZXMiID0gIlByb3RlY2Npb25fTk5BIiwNCiAgICAiUHJvdGVjY2nDs25fVmlvbGVuY2lhX0fDqW5lcm8iICAgICAgICAgPSAiUHJvdGVjY2lvbl9HQlYiKSkpICU+JSANCiAgIyByZW5hbWluZyBiZW5lZmljaWFyeSBkaXNhZ2dyZWdhdGlvbiBjb2x1bW5zIA0KICByZW5hbWUoZl8wXzE4ID0gZl8xOCwNCiAgICAgICAgIG1fMF8xOCA9IG1fMTgsDQogICAgICAgICBmXzE4cGx1cyA9IGZfMThfMiwNCiAgICAgICAgIG1fMThwbHVzID0gbV8xOF8yKSAlPiUgDQogIG11dGF0ZShlc3RhZG8gICAgPSBybV9hY2NlbnQoc3RyX3RvX3VwcGVyKGVzdGFkbykpLCANCiAgICAgICAgIG11bmljaXBpbyA9IHJtX2FjY2VudChzdHJfdG9fdXBwZXIobXVuaWNpcGlvKSksDQogICAgICAgICBwYXJyb3F1aWEgPSBybV9hY2NlbnQoc3RyX3RvX3VwcGVyKHBhcnJvcXVpYSkpLA0KICAgICAgICAgdWJpY2FjaW9uID0gcm1fYWNjZW50KHN0cl90b191cHBlcih1YmljYWNpb24pKSwNCiAgICAgICAgIGFjdGl2aWRhZCA9IHJtX2FjY2VudChzdHJfdG9fdXBwZXIoYWN0aXZpZGFkKSksDQogICAgICAgICBjYXRlZ29yaWEgPSBybV9hY2NlbnQoc3RyX3RvX3VwcGVyKGNhdGVnb3JpYWRlYWN0aXZpZGFkKSkpICU+JSANCiAgIyByZWNvZGluZyB0aGUgZXN0YXR1cyBjb2x1bW4gDQogIG11dGF0ZShlc3RhdHVzID0gc3RyX3JlcGxhY2VfYWxsKGVzdGF0dXMsIA0KICAgICAgICAgICAgICAgICAgYygiRW4gZWplY3VjaW9uIiA9ICJlamVjdWNpb24iLCANCiAgICAgICAgICAgICAgICAgICAgImVuIGVqZWN1Y2nDs24iID0gImVqZWN1Y2lvbiIsIA0KICAgICAgICAgICAgICAgICAgICAiZW4gRWplY3VjacOzbiIgPSAiZWplY3VjaW9uIiwNCiAgICAgICAgICAgICAgICAgICAgIkVuIGVqZWN1Y2nDs24iID0gImVqZWN1Y2lvbiIsDQogICAgICAgICAgICAgICAgICAgICJFbiBFamVjdWNpw7NuIiA9ICJlamVjdWNpb24iLA0KICAgICAgICAgICAgICAgICAgICAiRW5lamVjdWNpw7NuIiAgPSAiZWplY3VjaW9uIiwNCiAgICAgICAgICAgICAgICAgICAgIjQzNzQxIiAgICAgICAgPSAiZWplY3VjaW9uIiwNCiAgICAgICAgICAgICAgICAgICAgImZpbmFsaXphZGEiID0gImZpbmFsaXphZGEiLA0KICAgICAgICAgICAgICAgICAgICAiRmluYWxpemFkYSIgPSAiZmluYWxpemFkYSIsDQogICAgICAgICAgICAgICAgICAgICJQbGFuZWFkYSIgPSAicGxhbmVhZGEiLA0KICAgICAgICAgICAgICAgICAgICAicGxhbmVhZGEgY29uIGZpbmFuY2lhbWllbnRvIiA9ICJwbGFuZWFkYSIsDQogICAgICAgICAgICAgICAgICAgICJwbGFuZWFkYSBzaW4gZmluYW5jaWFtaWVudG8iID0gInBsYW5lYWRhIikpKSAlPiUgDQogIHJlcGxhY2VfbmEobGlzdChlc3RhdHVzID0gImVqZWN1Y2lvbiIpKSAlPiUgDQogICMgcmVtb3ZpbmcgYWxsIHBsYW5uZWQgYWN0aXZpdGllcyANCiAgZmlsdGVyKGVzdGF0dXMgIT0gInBsYW5lYWRhIikgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChwY29kZTMsICJeVkUiKSkgJT4lICMgZGVjaWRlIGlmIHlvdSB3YW50IHRvIGRvIHRoaXMgaGVyZSBvciBsYXRlcg0KICBzZWxlY3QoLWMoMjM6OTIpKQ0KDQojIEknbSBraW5kYSBkb3VidGluZyB0aGUgdXNlIG9mIHVfYmVuLCB5YSBJIHRoaW5rIHRha2UgaXQgb3V0PyBzaW5jZSB5b3UncmUgb25seSB1c2luZyBpdCBvbmNlDQojIEFtIEkganVzdCBtYWtpbmcgdGhlc2Ugb3V0IG9mIGhhYml0PyBJIGNvdWxkIG1ha2UgdGhlbSBpbnNpZGUgdGhlIA0KIyBjb2RlIGNodW5rIGZvciBwYXJyLCBidXQgbWF5YmUgSSBjYW4gZmluZCBzb21lIGp1c3RpZmljYXRpb24gZm9yIHRoZWlyIGV4aXN0ZW5jZSwgDQojIG1heWJlIHRoZSBkaXNhZ2dyZWdhdGlvbnM/IA0KDQojIFZhY2NpbmF0aW9uIGFjdGl2aXRpZXMgZmlsdGVyZWQgb3V0DQp1X2JlbiA8LSB2ZW4xICU+JSANCiAgcGl2b3RfbG9uZ2VyKGZfMF8xODptXzE4cGx1cywgbmFtZXNfdG8gPSAiZGVzYWdyZWdhY2lvbiIsIHZhbHVlc190byA9ICJiZW5lZmljaWFyaW9zIikgJT4lIA0KICBmaWx0ZXIoY2F0ZWdvcmlhZGVhY3RpdmlkYWQgIT0gIlZhY3VuYWNpb24iKSAlPiUgDQogIGZpbHRlcihiZW5lZmljaWFyaW9zICE9IDApICU+JSANCiAgZ3JvdXBfYnkodWJpY2FjaW9uLCBkZXNhZ3JlZ2FjaW9uKSAlPiUgDQogIHNsaWNlKHdoaWNoLm1heChiZW5lZmljaWFyaW9zKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KYWN0X2JlbiA8LSB2ZW4xICU+JSANCiAgcGl2b3RfbG9uZ2VyKGZfMF8xODptXzE4cGx1cywgbmFtZXNfdG8gPSAiZGVzYWdyZWdhY2lvbiIsIHZhbHVlc190byA9ICJiZW5lZmljaWFyaW9zIikgJT4lIA0KICBmaWx0ZXIoYmVuZWZpY2lhcmlvcyAhPSAwKSAlPiUgDQogIGdyb3VwX2J5KHViaWNhY2lvbiwgZGVzYWdyZWdhY2lvbiwgYWN0aXZpZGFkKSAlPiUgDQogIHNsaWNlKHdoaWNoLm1heChiZW5lZmljaWFyaW9zKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KIyByYmluZChzdW0odV9iZW4kYmVuZWZpY2lhcmlvcyksIA0KIyAgICAgICBzdW0oYWN0X2JlbiRiZW5lZmljaWFyaW9zKSwgDQojICAgICAgIHN1bSh1X2JlbiRiZW5lZmljaWFyaW9zKSAtIHN1bShhY3RfYmVuJGJlbmVmaWNpYXJpb3MpKQ0KDQpgYGANCg0KDQoNCmBgYHtyIG1ha2luZy1hbGwtcGFyci1hbmQtcGFycjB9DQojIEkgdGhpbmsgdGhpcyBpcyBhIGdpZ2FudGljIGNodW5rIC0tIGNhbm5vdCBkZWNpZGUgaWYgSSB3b3VsZCByYXRoZXIgaGF2ZSBsZXNzIHRoaW5ncyBpbiB0aGUgDQojIGVudmlyb25tZW50IG9yIGlmIEkgd2FudCBtb3JlIHJlYWRhYmxlIGNodW5rcy4gVGhlIGJlbmVmaXQgaGVyZSBJIGd1ZXNzIGlzIHRoYXQgaWYgSSB3YW50IHRvIGNoYW5nZSBzb21ldGhpbmcsIEkganVzdCBoYXZlIHRvIGNvbWUgdG8gdGhpcyBjaHVuaw0KDQpwYXJyIDwtIHVfYmVuICU+JSANCiAgZ3JvdXBfYnkocGNvZGUzKSAlPiUgDQogIHN1bW1hcmlzZShiZW5lZmljaWFyaW9zID0gc3VtKGJlbmVmaWNpYXJpb3MpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogICMgY291bnQgb2Ygb3JnYW5pc2F0aW9ucyBwZXIgcGNvZGUzDQogIGxlZnRfam9pbihhY3RfYmVuICU+JSANCiAgICAgICAgICAgICAjIGZpbHRlcihjYXRlZ29yaWEgIT0gIlZhY3VuYWNpb24iKSAlPiUNCiAgICAgICAgICAgICBncm91cF9ieShwY29kZTMpICU+JSANCiAgICAgICAgICAgICBzdW1tYXJpc2Uob3JnX2NvdW50ID0gbl9kaXN0aW5jdChvcmdfaW1wbGVtZW50YWRvcmEpKSkgJT4lIA0KICAjIGdldHRpbmcgYmVuZWZpY2lhcnkgZnJlcXVlbmNpZXMsIHNlY3RvciBjb3VudCBhbmQgbWF4aW11bSBtdWx0aS1zZWN0b3IgYmVuZWZpY2lhcmllcw0KICBsZWZ0X2pvaW4oYWN0X2JlbiAlPiUNCiAgIyB2YWNjaW5hdGlvbiBmaWx0ZXJlZCBvdXQgIA0KICAgZmlsdGVyKGNhdGVnb3JpYWRlYWN0aXZpZGFkICE9ICJWYWN1bmFjaW9uIikgJT4lIA0KICAgICAgICAgICAgIGdyb3VwX2J5KHViaWNhY2lvbiwgZGVzYWdyZWdhY2lvbiwgc2VjdG9yKSAlPiUgDQogICAgICAgICAgICAgICAgIHNsaWNlKHdoaWNoLm1heChiZW5lZmljaWFyaW9zKSkgJT4lIA0KICAgICAgICAgICAgICAgICB1bmdyb3VwKCkgJT4lDQogICAgICAgICAgICAgICAgIGdyb3VwX2J5KHViaWNhY2lvbiwgc2VjdG9yLCBwY29kZTMpICU+JSANCiAgICAgICAgICAgICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHNlY3RvciwgdmFsdWVzX2Zyb20gPSBiZW5lZmljaWFyaW9zKSAlPiUgDQogICAgICAgICAgICAgICAgIHJlcGxhY2VfbmEobGlzdChOdXRyaWNpb24gPSAwLCBFZHVjYWNpb24gPSAwLCBXQVNIID0gMCwgU2FsdWQgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2VndXJpZGFkX0FsaW1lbnRhcmlhID0gMCwgUHJvdGVjY2lvbl9OTkEgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvdGVjY2lvbl9HZW5lcmFsID0gMCwgUHJvdGVjY2lvbl9HQlYgPSAwKSkgJT4lDQogICAgICAgICAgICAgZ3JvdXBfYnkocGNvZGUzLCBkZXNhZ3JlZ2FjaW9uKSAlPiUgDQogICAgICAgICAgICAgc3VtbWFyaXNlKG51dHJpY2lvbl9iZW4gICA9IHN1bShOdXRyaWNpb24pLA0KICAgICAgICAgICAgICAgICAgICAgICBwcm90ZWNjaW9uX2JlbiAgPSBzdW0oUHJvdGVjY2lvbl9OTkEgKyBQcm90ZWNjaW9uX0dlbmVyYWwgKyBQcm90ZWNjaW9uX0dCViksDQogICAgICAgICAgICAgICAgICAgICAgIHdhc2hfYmVuICAgICAgICA9IHN1bShXQVNIKSwNCiAgICAgICAgICAgICAgICAgICAgICAgc2FsdWRfYmVuICAgICAgID0gc3VtKFNhbHVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZWR1Y2FjaW9uX2JlbiAgID0gc3VtKEVkdWNhY2lvbiksDQogICAgICAgICAgICAgICAgICAgICAgIHNhX2JlbiAgICAgICAgICA9IHN1bShTZWd1cmlkYWRfQWxpbWVudGFyaWEpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgDQogICAgICAgICAgICAgbXV0YXRlKGJlbl9mcmVxICAgPSBudXRyaWNpb25fYmVuICsgcHJvdGVjY2lvbl9iZW4gKyB3YXNoX2JlbiArIHNhbHVkX2JlbiArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZHVjYWNpb25fYmVuICsgc2FfYmVuLA0KICAgICAgICAgICAgICAgICAgICBiZW5fbWF4ICAgID0gcG1heChudXRyaWNpb25fYmVuLCBwcm90ZWNjaW9uX2Jlbiwgd2FzaF9iZW4sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYWx1ZF9iZW4sIGVkdWNhY2lvbl9iZW4sIHNhX2JlbiksDQogICAgICAgICAgICAgICAgICAgIG1zX2Jlbl9tYXggPSBpZmVsc2UoYmVuX21heCA+PSBiZW5fZnJlcSAtIGJlbl9tYXgsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlbl9mcmVxIC0gYmVuX21heCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmVuX21heCkpICU+JSANCiAgICAgICAgICAgICBncm91cF9ieShwY29kZTMpICU+JSANCiAgICAgICAgICAgICBzdW1tYXJpc2UobnV0cmljaW9uX2JlbiAgPSBzdW0obnV0cmljaW9uX2JlbiksDQogICAgICAgICAgICAgICAgICAgICAgIHByb3RlY2Npb25fYmVuID0gc3VtKHByb3RlY2Npb25fYmVuKSwNCiAgICAgICAgICAgICAgICAgICAgICAgd2FzaF9iZW4gICAgICAgPSBzdW0od2FzaF9iZW4pLA0KICAgICAgICAgICAgICAgICAgICAgICBzYWx1ZF9iZW4gICAgICA9IHN1bShzYWx1ZF9iZW4pLA0KICAgICAgICAgICAgICAgICAgICAgICBlZHVjYWNpb25fYmVuICA9IHN1bShlZHVjYWNpb25fYmVuKSwNCiAgICAgICAgICAgICAgICAgICAgICAgc2FfYmVuICAgICAgICAgPSBzdW0oc2FfYmVuKSwNCiAgICAgICAgICAgICAgICAgICAgICAgYmVuX2ZyZXEgICA9IHN1bShiZW5fZnJlcSksDQogICAgICAgICAgICAgICAgICAgICAgIGJlbl9tYXggICAgPSBzdW0oYmVuX21heCksDQogICAgICAgICAgICAgICAgICAgICAgIG1zX2Jlbl9tYXggPSBzdW0obXNfYmVuX21heCkpICU+JSANCiAgICAgICAgICAgICBtdXRhdGUoc2VjdG9yX2NvdW50ID0gcm93U3VtcyhzZWxlY3QoLiwgZW5kc193aXRoKCJfYmVuIikpICE9IDApKSkgJT4lICANCiAgZmlsdGVyKHN0cl9kZXRlY3QocGNvZGUzLCAiXlZFIikpICU+JSANCiAgIyByaWdodF9qb2luIHRvIHRoZSBjZW5zdXMgZGF0YQ0KICByaWdodF9qb2luKHJlYWRfZXhjZWwoImNlbnN1cyBkYXRhIDIwMTkxMTIyLnhsc3giLCBzaGVldCA9ICJkYXRhIikgJT4lIA0KICAgICAgICBjbGVhbl9uYW1lcygpICU+JSANCiAgICAgICAgIyBzZWxlY3RpbmcgdmFyaWFibGVzIGFuZCByZW5hbWluZyB0aGVtIHdpdGggc2VsZWN0DQogICAgICAgIHNlbGVjdChlc3RhZG8sIHBjb2RlMSwgbXVuaWNpcGlvLCBwY29kZTIsIHBhcnJvcXVpYSwgcGNvZGUzLCANCiAgICAgICAgICAgICAgIGZvID0gZmllbGRfb2ZmaWNlLA0KICAgICAgICAgICAgICAgcG9ibGFjaW9uXzIwMTkgPSB4XzIwMTlfcG9ibGFjaW9uX3BhcnJvcXVpYWxfdG90YWwsDQogICAgICAgICAgICAgICBob2dhcmVzXzIwMTEgPSBudW1lcm9fZGVfaG9nYXJlcywgDQogICAgICAgICAgICAgICBoYW1fMjAxOV9hbWJpdG9zX2dlLCANCiAgICAgICAgICAgICAgIHBlcmNlbnRfcG9icmUgPSBoYW1fMjAxOV94eF9wb2JyZXphX2Vudl9wb3JfcGFycm9xdWlhLCANCiAgICAgICAgICAgICAgIHBvYl9wb2JyZSA9IGhhbV8yMDE5X3h4X3BvYmxhY2lvbl9wb2JyZV9wb3JfcGFycm9xdWlhLCANCiAgICAgICAgICAgICAgIHBvYmxhY2lvbl90b3RhbF8yMDExLA0KICAgICAgICAgICAgICAgcG9ibGFjaW9uX2luZmFudGlsX21lbm9yX2RlXzEyX2Fub3MsIHBvYmxhY2lvbl9hZG9sZXNjZW50ZXNfZGVfMTJfYV8xN19hbm9zLA0KICAgICAgICAgICAgICAgcG9ibGFjaW9uX2RlXzE4X2Fub3NfeV9tYXMsIA0KICAgICAgICAgICAgICAgcGVyY2VudF91cmJhbmEgPSBwb2JsYWNpb25fdXJiYW5hX3BlcmNlbnQsIA0KICAgICAgICAgICAgICAgYXJlYV9rbTIsIA0KICAgICAgICAgICAgICAgZGVuc2lkYWRfcHBsX2ttMiA9IGRlbnNpZGFkX3BvYmxhY2lvbmFsX3BwbF9rbTIsDQogICAgICAgICAgICAgICBtYXRyaWN1bGFfMjAxN19lZHVjYWNpb25faW5pY2lhbCwgbWF0cmljdWxhXzIwMTdfZWR1Y2FjaW9uX3ByaW1hcmlhLCANCiAgICAgICAgICAgICAgIG1hdHJpY3VsYV8yMDE3X2VkdWNhY2lvbl9tZWRpYSwgcmF6b25fZGVfZGVwZW5kZW5jaWFfdG90YWwsDQogICAgICAgICAgICAgICByYXpvbl9kZV9kZXBlbmRlbmNpYV9kZV9tZW5vcmVzX2RlXzE1X2Fub3MsIA0KICAgICAgICAgICAgICAgcGVyY2VudF9zaW5fYWd1YV9zZWd1cmEgPSB4X2FiYXN0X2FndWEyX3BlcmNlbnRfc2luX2FndWFfc2VndXJhLA0KICAgICAgICAgICAgICAgcGVyY2VudF9zaW5fc2FuZWFtaWVudG9fbWVqb3JhZG8gPQ0KICAgICAgICAgICAgICAgICB4X3NhbmVhbWllbnRvX3BlcmNlbnRfc2luX3NhbmVhbWllbnRvX21lam9yYWRvLA0KICAgICAgICAgICAgICAgcGVyY2VudF9hbmFsZmFiZXRvID0gcGVyY2VudF9wb2JsYWNpb25fMTBfYW5vc195X21hc19hbmFsZmFiZXRhLA0KICAgICAgICAgICAgICAgcHJvbWVkaW9fZGVfcGVyc29uYXNfcG9yX3ZpdmllbmRhLA0KICAgICAgICAgICAgICAgcGVyY2VudF9ob2dhcmVzX2plZmF0dXJhX2ZlbWVuaW5hID0gcGVyY2VudF9kZV9ob2dhcmVzX2Nvbl9qZWZhdHVyYV9mZW1lbmluYSwNCiAgICAgICAgICAgICAgIHBlcmNlbnRfc2luX3NlcnZpY2lvX2VsZWN0cmljbyA9DQogICAgICAgICAgICAgICAgIHNlcnZpY2lvX2VsZWN0cmljb19wZXJjZW50X25vX3RpZW5lX3NlcnZpY2lvX2VsZWN0cmljbywNCiAgICAgICAgICAgICAgIGhhbV8yMDE5X3hfdmlvbGVuY2lhX2VudmVsb3BlLCBoYW1fMjAxOV94X21vcnRhbGlkYWRfeV9zYWx1ZF9lbnZlbG9wZSwgDQogICAgICAgICAgICAgICBoYW1fMjAxOV94X3BvYnJlemFfZW52ZWxvcGUsIHByb21lZGlvX2RlX2VkYWQpICU+JSANCiAgICAgICAgbXV0YXRlKGVzdGFkbyAgICAgPSBybV9hY2NlbnQoc3RyX3RvX3VwcGVyKGVzdGFkbykpLCAjIGp1c3QgdG8gbWFrZSBzdXJlIA0KICAgICAgICAgICAgICAgbXVuaWNpcGlvICA9IHJtX2FjY2VudChzdHJfdG9fdXBwZXIobXVuaWNpcGlvKSksDQogICAgICAgICAgICAgICBwYXJyb3F1aWEgID0gcm1fYWNjZW50KHN0cl90b191cHBlcihwYXJyb3F1aWEpKSkgJT4lIA0KICAgICAgICAjIGNyZWF0aW5nIG5ldyBkaXNhZ2dyZWdhdGlvbiB2YXJpYWJsZXMgDQogICAgICAgIG11dGF0ZShwb2JfbWVub3JfZGVfMTggPSAocG9ibGFjaW9uX2luZmFudGlsX21lbm9yX2RlXzEyX2Fub3MgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9ibGFjaW9uX2Fkb2xlc2NlbnRlc19kZV8xMl9hXzE3X2Fub3MpIC9wb2JsYWNpb25fdG90YWxfMjAxMSAqDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb2JsYWNpb25fMjAxOSwgDQogICAgICAgICAgICAgICBwb2JfMThfeV9tYXMgICAgPSBwb2JsYWNpb25fZGVfMThfYW5vc195X21hcyAvIHBvYmxhY2lvbl90b3RhbF8yMDExICogcG9ibGFjaW9uXzIwMTksIA0KICAgICAgICAgICAgICAgaG9nYXJlc18yMDE5ICAgID0gaG9nYXJlc18yMDExICogcG9ibGFjaW9uXzIwMTkgLyBwb2JsYWNpb25fdG90YWxfMjAxMSwgDQogICAgICAgICAgICAgICBtYXRyaWN1bGFfdG90YWwgPSBtYXRyaWN1bGFfMjAxN19lZHVjYWNpb25faW5pY2lhbCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF0cmljdWxhXzIwMTdfZWR1Y2FjaW9uX3ByaW1hcmlhICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXRyaWN1bGFfMjAxN19lZHVjYWNpb25fbWVkaWEpICU+JSANCiAgICAgICAgIyBkaXZpZGluZyBjb2x1bW5zIGJ5IDEwMCBzbyB0aGF0IHRoZXkncmUgYmV0d2VlbiAwIGFuZCAxDQogICAgICAgIG11dGF0ZV9hdCh2YXJzKHBlcmNlbnRfYW5hbGZhYmV0bywgcGVyY2VudF9zaW5fc2VydmljaW9fZWxlY3RyaWNvLCANCiAgICAgICAgICAgICAgICAgICAgICAgcGVyY2VudF9zaW5fYWd1YV9zZWd1cmEsDQogICAgICAgICAgICAgICAgICAgICAgIHBlcmNlbnRfc2luX3NhbmVhbWllbnRvX21lam9yYWRvLA0KICAgICAgICAgICAgICAgICAgICAgICBwZXJjZW50X2hvZ2FyZXNfamVmYXR1cmFfZmVtZW5pbmEsIHBlcmNlbnRfdXJiYW5hLA0KICAgICAgICAgICAgICAgICAgICAgICByYXpvbl9kZV9kZXBlbmRlbmNpYV90b3RhbCksIH4oLiAvIDEwMCkpICU+JSANCiAgICAgICAgIyBtdXRhdGluZyBuZXcgY29sdW1ucyB3aXRoIHBvcHVsYXRpb25zDQogICAgICAgIG11dGF0ZShwb2JfYW5hbGZhYmV0byAgICAgICAgICAgICAgID0gcGVyY2VudF9hbmFsZmFiZXRvICogcG9ibGFjaW9uXzIwMTksDQogICAgICAgICAgICAgICBwb2Jfc2luX2FndWFfc2VndXJhICAgICAgICAgID0gcGVyY2VudF9zaW5fYWd1YV9zZWd1cmEgKiBwb2JsYWNpb25fMjAxOSwgDQogICAgICAgICAgICAgICBwb2Jfc2luX3NlcnZpY2lvX2VsZWN0cmljbyAgID0gcGVyY2VudF9zaW5fc2VydmljaW9fZWxlY3RyaWNvICogcG9ibGFjaW9uXzIwMTksDQogICAgICAgICAgICAgICBwb2Jfc2luX3NhbmVhbWllbnRvX21lam9yYWRvID0gcGVyY2VudF9zaW5fc2FuZWFtaWVudG9fbWVqb3JhZG8gKiBwb2JsYWNpb25fMjAxOSwNCiAgICAgICAgICAgICAgIHBvYl91cmJhbmEgICAgICAgICAgICAgICAgICAgPSBwZXJjZW50X3VyYmFuYSAqIHBvYmxhY2lvbl8yMDE5KSAlPiUgDQogICAgICAgIHNlbGVjdCgtYyhtYXRyaWN1bGFfMjAxN19lZHVjYWNpb25faW5pY2lhbCwgbWF0cmljdWxhXzIwMTdfZWR1Y2FjaW9uX3ByaW1hcmlhLCANCiAgICAgICAgICAgICAgIG1hdHJpY3VsYV8yMDE3X2VkdWNhY2lvbl9tZWRpYSwgcG9ibGFjaW9uX3RvdGFsXzIwMTEsIGhvZ2FyZXNfMjAxMSwNCiAgICAgICAgICAgICAgIHBvYmxhY2lvbl9pbmZhbnRpbF9tZW5vcl9kZV8xMl9hbm9zLCBwb2JsYWNpb25fYWRvbGVzY2VudGVzX2RlXzEyX2FfMTdfYW5vcywgDQogICAgICAgICAgICAgICBwb2JsYWNpb25fZGVfMThfYW5vc195X21hcykpLA0KICAgICAgICAgICAgYnkgPSAicGNvZGUzIikgJT4lIA0KICAjIG11dGF0aW5nIG5ldyB2YXJpYWJsZXMgYW5kIG1ha2luZyBzdXJlIE5BcyBiZWNvbWUgMHMgDQogIG11dGF0ZShiZW5lZmljaWFyaW9zICA9IGlmZWxzZShpcy5uYShiZW5lZmljaWFyaW9zKSwgMCwgYmVuZWZpY2lhcmlvcyksDQogICAgICAgICBvcmdfY291bnQgICAgICA9IGlmZWxzZShpcy5uYShvcmdfY291bnQpLCAwLCBvcmdfY291bnQpLA0KICAgICAgICAgc2VjdG9yX2NvdW50ICAgPSBpZmVsc2UoaXMubmEoc2VjdG9yX2NvdW50KSwgMCwgc2VjdG9yX2NvdW50KSwgDQogICAgICAgICBlZHVjYWNpb25fYmVuICA9IGlmZWxzZShpcy5uYShlZHVjYWNpb25fYmVuKSwgMCwgZWR1Y2FjaW9uX2JlbiksDQogICAgICAgICBudXRyaWNpb25fYmVuICA9IGlmZWxzZShpcy5uYShudXRyaWNpb25fYmVuKSwgMCwgbnV0cmljaW9uX2JlbiksDQogICAgICAgICBwcm90ZWNjaW9uX2JlbiA9IGlmZWxzZShpcy5uYShwcm90ZWNjaW9uX2JlbiksIDAsIHByb3RlY2Npb25fYmVuKSwNCiAgICAgICAgIHNhbHVkX2JlbiAgICAgID0gaWZlbHNlKGlzLm5hKHNhbHVkX2JlbiksIDAsIHNhbHVkX2JlbiksDQogICAgICAgICBzYV9iZW4gICAgICAgICA9IGlmZWxzZShpcy5uYShzYV9iZW4pLCAwLCBzYV9iZW4pLA0KICAgICAgICAgd2FzaF9iZW4gICAgICAgPSBpZmVsc2UoaXMubmEod2FzaF9iZW4pLCAwLCB3YXNoX2JlbiksDQogICAgICAgICBtc19iZW5fbWF4ICAgICA9IGlmZWxzZShpcy5uYShtc19iZW5fbWF4KSwgMCwgbXNfYmVuX21heCksDQogICAgICAgICBiZW5fZnJlcSAgICAgICA9IGlmZWxzZShpcy5uYShiZW5fZnJlcSksIDAsIGJlbl9mcmVxKSwNCiAgICAgICAgIG5vdF9yZWFjaGVkICAgICAgICAgICAgPSBwb2JfcG9icmUgLSBiZW5lZmljaWFyaW9zLA0KICAgICAgICAgY292ZXJhZ2VfcGVyY2VudCAgICAgICA9IGJlbmVmaWNpYXJpb3MgLyBwb2JsYWNpb25fMjAxOSwNCiAgICAgICAgIGNvdmVyYWdlX3BvYnJlX3BlcmNlbnQgPSBiZW5lZmljaWFyaW9zIC8gcG9iX3BvYnJlLA0KICAgICAgICAgcGVyY2VudF90b3RhbF9iZW4gICAgICA9IGJlbmVmaWNpYXJpb3MgLyBzdW0oYmVuZWZpY2lhcmlvcyksDQogICAgICAgICBtdWx0aXNlY3Rvcl9wZXJjZW50ICAgID0gbXNfYmVuX21heCAvIGJlbl9mcmVxLCANCiAgICAgICAgIG9yZ19wcmVzZW50ICAgICAgICAgICAgPSBpZmVsc2UoYmVuZWZpY2lhcmlvcyA+IDAsIFRSVUUsIEZBTFNFKSwNCiAgICAgICAgIHBvYl9wb2JyZV9zY29yZSAgICAgPSByZXNjYWxlKHBvYl9wb2JyZSwgdG8gPSBjKDAsMSkpLCANCiAgICAgICAgIHBlcmNlbnRfcG9icmVfc2NvcmUgPSByZXNjYWxlKHBlcmNlbnRfcG9icmUsIHRvID0gYygwLDEpKSwgDQogICAgICAgICBwb3ZlcnR5X3Njb3JlICAgICAgID0gKHBvYl9wb2JyZV9zY29yZSArIHBlcmNlbnRfcG9icmVfc2NvcmUpIC8gMikNCg0KIyB0YWtpbmcgYSBzdWJzZXQgb2YgcGFyciB0byBvbmx5IGdldCBwYXJyaXNoZXMgd2hlcmUgdGhlIG51bWJlciBvZiBiZW5lZmljaWFyaWVzIGRvZXMgbm90IGV4Y2VlZCB0aGUgbnVtYmVyIG9mIHBvb3IgcGVyc29ucw0KDQpwYXJyMCA8LSBwYXJyICU+JSANCiAgZmlsdGVyKG5vdF9yZWFjaGVkID49IDEpICU+JSANCiAgbXV0YXRlKGdhcF9zY29yZSA9IChyZXNjYWxlKG5vdF9yZWFjaGVkLCB0byA9IGMoMCwxKSkgKyBwZXJjZW50X3BvYnJlX3Njb3JlKSAvIDIpDQoNCmBgYA0KDQpgYGB7ciB3cml0ZS1jc3YtcGFycjAsIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9IEZBTFNFfQ0KIyBldmFsbGVkIG91dCAtLSBjaGFuZ2UgdGhpcyBpZiB5b3Ugd2FudCB0aGUgY3N2IGZvciB0YWJsZWF1IG9yIHdoYXRldmVyDQp3cml0ZV9jc3YocGFycjAsICJwYXJyMC5jc3YiKQ0KYGBgDQoNCiMjIDIuIFN1bW1hcnkgb2YgY292ZXJhZ2UgYW5kIGdhcHMNCg0KIyMjIDJhLiBNYXAgb2YgcGFycmlzaGVzIGJ5IGdhcHMNCg0KYGBge3IgTUFQLVJFRiwgaW5jbHVkZSA9IEZBTFNFfQ0KIyByZWFkaW5nIGluIHRoZSBzaGFwZWZpbGUNCnBjb2RlM19zaGFwZSA8LSBzdF9yZWFkKCJDOi9Vc2Vycy9TZWFuIE5nL0RvY3VtZW50cy9SL2NvdmVyYWdlX2dhcHNfdmVuZXp1ZWxhL3Zlbl9hZG1ibmRhX2FkbTNfMjAxODA1MDIvdmVuX2FkbWJuZGFfYWRtM18yMDE4MDUwMi5zaHAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgcXVpZXQgPSBUUlVFKSAlPiUgDQogIHJlbmFtZShwY29kZTEgPSBBRE0xX1BDT0RFLA0KICAgICAgICAgcGNvZGUyID0gQURNMl9QQ09ERSwNCiAgICAgICAgIHBjb2RlMyA9IEFETTNfUENPREUpICU+JSANCiAgbXV0YXRlKHBjb2RlMyA9IHJlY29kZShwY29kZTMsDQogICAgICAgICAgICAgICAgICAgICAgICAgIlZFMDMwMTAyIiA9ICJWRTAzMDEwMSIsICMgb25seSBBbmFjbyBleGlzdHMsIGFjY29yZGluZyB0byB0aGUgY2Vuc3VzDQogICAgICAgICAgICAgICAgICAgICAgICAgIlZFMDMxOTAxIiA9ICJWRTAzMTkwMCIsICMgc29tZWhvdyB0aGUgY2Vuc3VzIGFuZCB0aGUgc2hhcGVmaWxlcyBjb25mbGljdA0KICAgICAgICAgICAgICAgICAgICAgICAgICJWRTA3MDMwMSIgPSAiVkUwNzAzMDAiKSkgJT4lICAjIGhlcmUgdG9vDQojIHNpbXBseWluZyB0byByZW1vdmUgc2xpdmVycyAtLSBsZXQncyBzZWUgaWYgdGhpcyB3b3JrcyANCiMgaXQncyBhIGJpdCBhYnN0cmFjdCBhdCAwLjA1LCBidXQgdGhlIHNsaXZlcnMgQVJFIGdvbmUgYW5kIGl0IGxvb2tzIG5vdCBiYWQgDQojIGZpZ3VyaW5nIHRoaXMgb3V0IHdhcyBtYWRkZW5pbmcsIEkgY2FuJ3QgYmVsaWV2ZSB5b3Ugc3BlbnQgc28gbG9uZyBvbiBjb3NtZXRpYyBpdGVtcyANCiAgbXNfc2ltcGxpZnkoa2VlcCA9IDAuMDUsIGtlZXBfc2hhcGVzID0gVFJVRSkNCg0KYGBgDQoNCmBgYHtyIGNvdmVyYWdlLW1hcC1ub3QtY292ZXJlZC1wb2JyZX0NCiMgcGFycmlzaGVzIHdpdGggbmVnYXRpdmUgcG9vciBwZXJzb25zIGFyZSByZWNvZGVkIGFzICIwIiBzbyB0aGV5IHdvbid0IG1lc3MgdXAgdGhlIHNjYWxlDQojIGV2ZW4gdGhvdWdoIHRoaXMgbWVhbnMgdGhhdCB0aGVpciB0b29sdGlwcyBhcmUgZHJvcHBlZCANCg0KZ2Fwc19tYXAgPC0gcGFyciAlPiUgDQogIHJpZ2h0X2pvaW4ocGNvZGUzX3NoYXBlLCBieSA9ICJwY29kZTMiKSAlPiUgDQogIHN0X2FzX3NmKCkgJT4lIA0KICBtdXRhdGUobm90X3JlYWNoZWQgPSBpZmVsc2Uobm90X3JlYWNoZWQgPCAwLjEsIDAsIG5vdF9yZWFjaGVkKSkgJT4lIA0KICBtdXRhdGUobm90X3JlYWNoZWQgPSByb3VuZChub3RfcmVhY2hlZCwgZGlnaXRzID0gMCkpICU+JQ0KICBtdXRhdGVfYXQodmFycyhwZXJjZW50X3BvYnJlLCBwZXJjZW50X3VyYmFuYSksIH4ocm91bmQoLiwgZGlnaXRzID0gMikpKSAlPiUgDQogIGdncGxvdCgpICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IG5vdF9yZWFjaGVkLA0KICAgICAgICAgICAgICB0ZXh0ID0gcGFzdGUwKHBhcnJvcXVpYSwiLCIsICJcbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbXVuaWNpcGlvLCAiLCIsICJcbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RhZG8sICJcbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5vdCByZWFjaGVkOiAiLCBub3RfcmVhY2hlZCwgIlxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmcgY291bnQ6ICIsIG9yZ19jb3VudCwgIlxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3ZlcnR5IGluY2lkZW5jZTogIiwgcGVyY2VudF9wb2JyZSwgIlxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50IHVyYmFuOiAiLCBwZXJjZW50X3VyYmFuYSkpLA0KICAgICAgICAgIHNpemUgPSAwLjEpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gInR1cmJvIiwgdHJhbnMgPSAibG9nMTAiKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArDQogIGxhYnMoZmlsbCA9ICJQb29yIHBlcnNvbnMgXG5ub3QgcmVhY2hlZCIpICsNCiAgZ2d0aXRsZSgiTWFwIG9mIHBhcnJpc2hlcyBieSBnYXBzIGluIHBvcHVsYXRpb24gcmVhY2hlZCIpDQoNCiMgc28gYXJlIHlvdSBzYXlpbmcgdGhhdCBpZiBJIGNoYW5nZSB0aGUgZmlsbCB0byB2aXJpZGlzIGluIHRoZSBsYXRlciBwbG90LCBJIGNhbiB1c2UgaG92ZXJvbiA9IGZpbGw/DQojIG5vIHlvdSBjYW4ndC4gDQpnZ3Bsb3RseShnYXBzX21hcCwgdG9vbHRpcCA9IGMoInRleHQiKSkgJT4lDQogIGxheW91dChzaG93bGVnZW5kID0gVFJVRSwgbGVnZW5kID0gbGlzdChmb250ID0gbGlzdChzaXplID0gNikpKSAlPiUgDQogIHN0eWxlKGhvdmVyb24gPSAiZmlsbCIpICU+JSANCiAgbGF5b3V0KHRpdGxlID0gbGlzdCh0ZXh0ID0gcGFzdGUwKCJNYXAgb2YgcGFycmlzaGVzIGJ5IG51bWJlciBwb29yIHBlcnNvbnMgbm90IHJlYWNoZWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxzdXA+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtb3VzZSBvdmVyIGZvciBkZXRhaWxzOyBkcmFnIGFuZCBjbGljayB0byBzZWxlY3QgYW5kIHpvb207IGRvdWJsZS1jbGljayBsZWdlbmQgc2VsZWN0L2Rlc2VsZWN0IiwiPC9zdXA+IikpKQ0KDQpgYGANCg0KTmF0aW9ud2lkZSwgKipgciBmb3JtYXQocm91bmQoc3VtKHBhcnIwJG5vdF9yZWFjaGVkKSwgZGlnaXRzID0gMCksIGJpZy5tYXJrID0gIiwiKWAqKiBwb29yIHBlcnNvbnMgaGF2ZSBub3QgYmVlbiByZWFjaGVkIGJ5IHJlc3BvbnNlIGFjdGl2aXRpZXMgLS0gdGhpcyBtZWFucyB0aGF0ICoqYHIgcm91bmQoc3VtKHBhcnIwJG5vdF9yZWFjaGVkKSAvIHN1bShwYXJyMCRwb2JfcG9icmUpICogMTAwLCBkaWdpdHMgPSAxKWAlKiogYWxsIHRoZSBwb29yIHBlcnNvbnMgaW4gdGhlIGNvdW50cnkgaGF2ZSB5ZXQgdG8gYmUgcmVhY2hlZC4gDQoNCjxicj4NCg0KIyMjIDJiLiBHcm91cGluZyBwYXJyaXNoZXMgYnkgY292ZXJhZ2UNCg0KQXMgYSBzdGFydGluZyBwb2ludCwgYWxsIGByIG5yb3cocGFycilgIHBhcnJpc2hlcyBoYXZlIGJlZW4gc3BsaXQgaW50byB0aHJlZSBncm91cHMgLS0gX292ZXJfLCB3aGVyZSB0aGUgbnVtYmVyIG9mIHVuaXF1ZSBiZW5lZmljaWFyaWVzIHJlYWNoZWQgZXhjZWVkcyB0aGUgbnVtYmVyIG9mIHBvb3IgcGVyc29ucyBpbiB0aGF0IHBhcnJpc2g7IF91bmRlcl8sIHdoZXJlIHRoZSBjb3ZlcmFnZSBpcyBsZXNzIHRoYW4gdGhlIG51bWJlciBvZiBwb29yIHBlcnNvbnM7IGFuZCBfbm8gY292ZXJhZ2VfLCBjb21wcmlzaW5nIGEgdG90YWwgb2YgYHIgbnJvdyhmaWx0ZXIocGFyciwgYmVuZWZpY2lhcmlvcyA9PSAwKSlgIHBhcnJpc2hlcywgd2hlcmUgbm8gYWN0aXZpdGllcyBoYXZlIG9jY3VycmVkLiANCg0KSG93ZXZlciwgaXQgc2hvdWxkIGJlIG5vdGVkIHRoYXQgYSB0b3RhbCBvZiAqKmByIHJvdW5kKHN1bShwYXJyMCRub3RfcmVhY2hlZCksIGRpZ2l0cyA9IDApICU+JSBmb3JtYXQoYmlnLm1hcmsgPSAiLCIpYCoqIHBvb3IgcGVyc29ucyByZXNpZGUgaW4gdGhlICoqYHIgbnJvdyhmaWx0ZXIocGFyciwgYmVuZWZpY2lhcmlvcyA9PSAwKSlgKiogcGFycmlzaGVzIHRoYXQgaGF2ZSBub3QgYmVlbiByZWFjaGVkLCB0aGlzIGlzIG9ubHkgKipgciByb3VuZChmaWx0ZXIocGFyciwgYmVuZWZpY2lhcmlvcyA9PSAwKSAlPiUge3N1bSguJHBvYl9wb2JyZSl9IC8gc3VtKHBhcnIkbm90X3JlYWNoZWQpICoxMDAsIGRpZ2l0cyA9IDApYCUqKiBvZiB0aGUgKipgciByb3VuZChzdW0ocGFyciRub3RfcmVhY2hlZCksIGRpZ2l0cyA9IDApICU+JSBmb3JtYXQoYmlnLm1hcmsgPSAiLCIpYCoqIHBvb3IgcGVyc29ucyBub3QgY292ZXJlZCBieSByZXNwb25zZSBhY3Rpdml0aWVzLiBUaGlzIGluZGljYXRlcyB0aGF0IDEpIHRoZXJlIGlzIG11Y2ggcm9vbSB0byBleHBhbmQgaW4gdGhlIHBhcnJpc2hlcyB3aGVyZSB3ZSBhcmUgYWxyZWFkeSBwcmVzZW50IGFuZCB0aGF0IDIpIHNwYXJlbHkgcG9wdWxhdGVkLCByZW1vdGUgYW5kLCBjb25zZXF1ZW50bHksIHBvb3JlciBwYXJyaXNoZXMgaGF2ZSwgc28gZmFyLCBiZWVuIGxlZnQgb3V0IG9mIHRoZSByZXNwb25zZS4gDQoNCg0KYGBge3J9DQpwYXJyICU+JSANCiAgbXV0YXRlKGNvdmVyYWdlX3R5cGUgPSBjYXNlX3doZW4obm90X3JlYWNoZWQgPD0gMCB+ICJvdmVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90X3JlYWNoZWQgPiAwICYgYmVuZWZpY2lhcmlvcyA+PSAxIH4gInVuZGVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlbmVmaWNpYXJpb3MgPT0gMCB+ICJub19jb3ZlcmFnZSIpKSAlPiUgDQogIGdyb3VwX2J5KGNvdmVyYWdlX3R5cGUpICU+JSANCiAgc3VtbWFyaXNlKHBhcnJvcXVpYXMgPSBuKCksDQogICAgICAgICAgICBiZW5lZmljaWFyaW9zID0gc3VtKGJlbmVmaWNpYXJpb3MpLA0KICAgICAgICAgICAgbm90X3JlYWNoZWQgPSBzdW0obm90X3JlYWNoZWQpLCANCiAgICAgICAgICAgIGF2Z19vcmdfY291bnQgPSBtZWFuKG9yZ19jb3VudCksDQogICAgICAgICAgICBwZXJjZW50X3BvYnJlID0gKHN1bShwb2JfcG9icmUpKSAvIChzdW0ocG9ibGFjaW9uXzIwMTkpKSwNCiAgICAgICAgICAgIHBlcmNlbnRfdXJiYW5hID0gKHN1bShwb2JfdXJiYW5hKSkgLyAoc3VtKHBvYmxhY2lvbl8yMDE5KSksDQogICAgICAgICAgICBwZXJjZW50X3Npbl9hZ3VhX3NlZ3VyYSA9IChzdW0ocG9iX3Npbl9hZ3VhX3NlZ3VyYSkpIC8gKHN1bShwb2JsYWNpb25fMjAxOSkpLA0KICAgICAgICAgICAgcGVyY2VudF9zaW5fc2FuZWFtaWVudG9fbWVqb3JhZG8gPSAoc3VtKHBvYl9zaW5fc2FuZWFtaWVudG9fbWVqb3JhZG8pKSAvDQogICAgICAgICAgICAgIChzdW0ocG9ibGFjaW9uXzIwMTkpKSwNCiAgICAgICAgICAgIGF2Z19zZWN0b3JfY291bnQgPSBtZWFuKHNlY3Rvcl9jb3VudCkpICU+JSANCiAgZ2F0aGVyKGtleSA9IHZhcmlhYmxlLCB2YWx1ZSA9IHZhbHVlLCAyOm5jb2woLikpICU+JSANCiAgc3ByZWFkXyhrZXkgPSBuYW1lcyguKVsxXSwgdmFsdWUgPSAndmFsdWUnKSAlPiUgDQogIHJlbG9jYXRlKG5vX2NvdmVyYWdlLCAuYWZ0ZXIgPSB1bmRlcikgJT4lIA0KICBwYW5kZXIoYmlnLm1hcmsgPSAiLCIpDQoNCg0KYGBgDQoNCldlIG5vdGUgdGhhdCB0aGUgKipgciBucm93KHBhcnJbcGFyciRub3RfcmVhY2hlZCA8PSAwLF0pYCoqIHBhcnJpc2hlcyBpbiB0aGUgX292ZXJfIGNhdGVnb3J5IGFyZSBtdWNoIGxlc3MgcG9vciBhbmQgbXVjaCBtb3JlIHVyYmFuIGRlc3BpdGUgaGF2aW5nICoqYHIgcm91bmQoZmlsdGVyKHBhcnIsIG5vdF9yZWFjaGVkIDw9IDApICU+JSB7c3VtKC4kYmVuZWZpY2lhcmlvcyl9IC8gc3VtKHBhcnIkYmVuZWZpY2lhcmlvcykgKiAxMDAsIGRpZ2l0cyA9IDApYCUqKiBvZiBhbGwgYmVuZWZpY2lhcmllcy4gVGhlc2UgcGFycmlzaGVzIGFyZSBzaG93biBpbiB0aGUgdGFibGUgYmVsb3cuIEFuZCwgYXMgY2FuIGJlIHNlZW4gZnJvbSBgbm90X3JlYWNoZWRgLCB0aGUgbnVtYmVyIGJlbmVmaWNpYXJpZXMgaW4gdGhlIF9vdmVyXyBjYXRlZ29yeSBoYXMgZ3JlYXRseSBleGNlZWRlZCB0aGUgbnVtYmVyIG9mIHBvb3IgcGVyc29ucy4gDQoNCjxicj4NCg0KIyMjIDJjLiBUb3AgcGFycmlzaGVzIGluIHRlcm1zIG9mIGNvdmVyYWdlDQoNClBhcnJpc2hlcyAoYWRtaW4gbGV2ZWwgMykgd2lsbCBiZSB0aGUgbWFpbiBhZG1pbmlzdHJhdGl2ZSB1bml0IG9mIHJlZmVyZW5jZS4gVW5saWtlIGluIHRoZSA1VyBjbGVhbmluZyBhbmQgcmVwb3J0aW5nIGRvY3VtZW50LCB3aGVyZSB3ZSBmb2N1c2VkIG9uIG11bmljaXBhbGl0aWVzLCBncmVhdGVyIHByZWNpc2lvbiBpcyBuZWVkZWQgZm9yIGEgY292ZXJhZ2UgYW5kIGdhcHMgYW5hbHlzaXMuIEZ1cnRoZXJtb3JlLCB3ZSBzaG91bGQgYWx3YXlzIGVuZGVhdm91ciB0byBtYXhpbWlzZSB0aGUgdXNhZ2Ugb2YgYWxsIGF2YWlsYWJsZSBkYXRhLiANCg0KVGhlICoqYHIgbnJvdyhwYXJyW3BhcnIkbm90X3JlYWNoZWQgPD0gMCxdKWAqKiBwYXJyaXNoZXMgYmVsb3cgd2lsbCBsYXJnZWx5IGJlIGV4Y2x1ZGVkIGluIHRoZSAgcmVtYWluZGVyIG9mIHRoaXMgcmVwb3J0IGFzIGl0IGlzIGNsZWFyIHRoYXQgbm8gZnVydGhlciByZXNvdXJjZXMgc2hvdWxkIGJlIGFsbG9jYXRlZCB0byB0aGVtOiANCg0KYGBge3J9DQpwYXJyICU+JSANCiAgbXV0YXRlKGNvdmVyYWdlX3R5cGUgPSBjYXNlX3doZW4obm90X3JlYWNoZWQgPD0gMCB+ICJvdmVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm90X3JlYWNoZWQgPiAwICYgYmVuZWZpY2lhcmlvcyA+PSAxIH4gInVuZGVyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlbmVmaWNpYXJpb3MgPT0gMCB+ICJub3RfcmVhY2hlZCIpKSAlPiUgIA0KICBmaWx0ZXIoY292ZXJhZ2VfdHlwZSA9PSAib3ZlciIpICU+JSANCiAgc2VsZWN0KGVzdGFkbywgbXVuaWNpcGlvLCBlc3RhZG8sIHBhcnJvcXVpYSwgYmVuZWZpY2lhcmlvcywgcG9iX3BvYnJlKSAlPiUNCiAgbXV0YXRlKGNvdmVyYWdlX3BlcmNlbnQgPSBiZW5lZmljaWFyaW9zIC8gcG9iX3BvYnJlICogMTAwKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhiZW5lZmljaWFyaW9zKSkgJT4lIA0KICBwYW5kZXIoYmlnLm1hcmsgPSAiLCIpDQoNCmBgYA0KDQpUaG91Z2ggaXQgc2hvdWxkIGJlIG1lbnRpb25lZCB0aGF0IGl0IGlzIGxpa2VseSB0aGF0IHBhcnRuZXJzIGhhdmUgcmVwb3J0ZWQgYWN0aXZpdGllcyB3aGljaCBvY2N1cnJlZCBpbiBvdGhlciBwYXJ0cyBvZiB0aGUgY2FwaXRhbCBpbiBBbHRhZ3JhY2lhLCBhcyB0aGUgdG90YWwgbnVtYmVyIG9mIGJlbmVmaWZpY2FyaWVzIHJlYWNoZWQgaW4gdGhlIHdob2xlIG9mIERpc3RyaXRvIENhcGl0YWwgaXMgb25seSBgciBzdW1tYXJpc2UocGFyciwgYmVuZWZpY2lhcmlvcyA9IHN1bShiZW5lZmljaWFyaW9zW211bmljaXBpbyA9PSAiTElCRVJUQURPUiJdKSkgJT4lIGZvcm1hdChiaWcubWFyayA9ICIsIilgLiBJdCBpcyBuZWNlc3NhcnkgdG8gY2hlY2sgYmFjayB3aXRoIHBhcnRuZXJzIGFib3V0IHRoaXM7IG5ldmVydGhlbGVzcywgdGhpcyBpcyB0aGUgaW5mb3JtYXRpb24gd2UgaGF2ZSBvbiBoYW5kLiANCg0KPGJyPg0KDQojIyAzLiBHZW9ncmFwaGljYWwgYW5hbHlzaXMgb2YgR2Fwcw0KDQojIyMgM2EuIEJhcnBsb3Qgb2YgY292ZXJhZ2UgYW5kIGdhcHMgYnkgc3RhdGUNCl9tb3VzZSBvdmVyIHBsb3QgZm9yIG1vcmUgZGV0YWlsc18NCg0KYGBge3IgcGFycjAtc3RhdGUtUExPVCwgZmlnLmhlaWdodD01fQ0KIyByZWYgZm9yIHByaW50aW5nIHN0YXRlX29yZC4gSSdtIHJlYWxseSBub3Qgc3VyZSBob3cgdG8gZXh0cmFjdCBhbGwgdGhlIHZhcmlhYmxlcyBhcyBhIGxpc3QNCiMgcGFycjAgJT4lIA0KIyAgIGdyb3VwX2J5KGVzdGFkbykgJT4lIA0KIyAgIHN1bW1hcmlzZShub3RfcmVhY2hlZCA9IHN1bShub3RfcmVhY2hlZCkpICU+JSANCiMgICBhcnJhbmdlKGRlc2Mobm90X3JlYWNoZWQpKSAlPiUgDQojICAgc2VsZWN0KGVzdGFkbykgJT4lIGFzLmxpc3QoYXMuZGF0YS5mcmFtZSh0KC4pKSkNCg0Kc3RhdGVfb3JkIDwtIGMoIlpVTElBIiwgIkxBUkEiLCAiQ0FSQUJPQk8iLCAiTUlSQU5EQSIsICJBTlpPQVRFR1VJIiwgIkFSQUdVQSIsICJCT0xJVkFSIiwNCiAgICAgICAgICAgICAgICJQT1JUVUdVRVNBIiwgIlNVQ1JFIiwgIkdVQVJJQ08iLCAiRkFMQ09OIiwgIk1PTkFHQVMiLCAiQkFSSU5BUyIsICJNRVJJREEiLA0KICAgICAgICAgICAgICAgIlRBQ0hJUkEiLCAiVFJVSklMTE8iLCAiWUFSQUNVWSIsICJBUFVSRSIsICJESVNUUklUTyBDQVBJVEFMIiwgIk5VRVZBIEVTUEFSVEEiLA0KICAgICAgICAgICAgICAgIkNPSkVERVMiLCAiVkFSR0FTIiwgIkRFTFRBIEFNQUNVUk8iLCAiQU1BWk9OQVMiKQ0KICANCnN0YWNrX3RleHQgPC0gcGFycjAgJT4lIA0KICBncm91cF9ieShlc3RhZG8pICU+JSANCiAgc3VtbWFyaXNlKGJlbmVmaWNpYXJpb3MgPSBzdW0oYmVuZWZpY2lhcmlvcyksDQogICAgICAgICAgICB0b3RhbCA9IHN1bShwb2JfcG9icmUpKSAlPiUgDQogIG11dGF0ZShwZXJjZW50X3JlYWNoZWQgPSByb3VuZChiZW5lZmljaWFyaW9zIC8gdG90YWwgKiAxMDAsIGRpZ2l0cyA9IDIpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyh0b3RhbCkpIA0KDQpzdGF0ZV9zdGFjayA8LSBwYXJyMCAlPiUgDQogIHNlbGVjdChlc3RhZG8sIGJlbmVmaWNpYXJpb3MsIG5vdF9yZWFjaGVkKSAlPiUgDQogIGdyb3VwX2J5KGVzdGFkbykgJT4lDQogIHN1bW1hcmlzZShiZW5lZmljaWFyaW9zID0gcm91bmQoc3VtKGJlbmVmaWNpYXJpb3MpLCBkaWdpdHMgPSAwKSwgDQogICAgICAgICAgICBub3RfcmVhY2hlZCA9IHJvdW5kKHN1bShub3RfcmVhY2hlZCksIGRpZ2l0cyA9IDApKSAlPiUgDQogIHBpdm90X2xvbmdlcihjKGJlbmVmaWNpYXJpb3Msbm90X3JlYWNoZWQpLA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAicG9iX3R5cGUiLCB2YWx1ZXNfdG8gPSAidG90YWwiKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBlc3RhZG8sIHkgPSB0b3RhbCkpICsNCiAgZ2VvbV9jb2woYWVzKGZpbGwgPSBwb2JfdHlwZSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVsID0gY29tbWEpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBzdGF0ZV9vcmQpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiY29yYWwiLCAiY29ybmZsb3dlcmJsdWUiKSkgKw0KICBnZW9tX3RleHQoZGF0YSA9IHN0YWNrX3RleHQsIGFlcyh5ID0gMjAwMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGVyY2VudF9yZWFjaGVkKSwgc2l6ZSA9IDIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDUpLA0KICAgICAgICBheGlzLnRleHQueSAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLA0KICAgICAgICBwbG90LnRpdGxlICAgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSkgKw0KICB4bGFiKCIiKSArIHlsYWIoIlBvb3IgcGVyc29ucyIpICsgDQogIGxhYnMoZmlsbCA9ICIiLA0KICAgICAgIHRpdGxlID0gIkJhcnBsb3Qgb2YgcG9vciBwZXJzb25zIGJ5IHN0YXRlIikNCg0KZ2dwbG90bHkoc3RhdGVfc3RhY2spICU+JSANCiAgbGF5b3V0KGxlZ2VuZCA9IGxpc3QoZm9udCA9IGxpc3Qoc2l6ZSA9IDYpKSkgJT4lIA0KICBjb25maWcoZGlzcGxheU1vZGVCYXIgPSBGQUxTRSkNCg0KYGBgDQoNClRoZSBzdGF0ZXMgd2hlcmUgdGhlIGhpZ2hlc3QgcHJvcG9ydGlvbnMgb2YgcG9vciBwZXJzb25zIGhhdmUgYmVlbiByZWFjaGVkIChsaXN0ZWQgYXQgdGhlIGJvdHRvbSBvZiBlYWNoIGJhcikgYXJlIERpc3RyaXRvIENhcGl0YWwsIFRhY2hpcmEsIEJvbGl2YXIsIERlbHRhIEFtYWN1cm8sIE1pcmFuZGEgYW5kIFp1bGlhLiBDYXJhYm9ibyBoYXMgdGhlIGxvd2VzdCBwZXJjZW50YWdlIG9mIGl0cyBwb29yIHBvcHVsYXRpb24gY292ZXJlZC4gT24gYXZlcmFnZSwgYWZ0ZXIgdGhlIGV4Y2x1c2lvbiBvZiB0aGUgdG9wIGByIG5yb3cocGFycltwYXJyJG5vdF9yZWFjaGVkIDw9IDAsXSlgIHBhcnJpc2hlcywgKipgciByb3VuZChzdW0ocGFyciRiZW5lZmljaWFyaW9zKSAvIHN1bShwYXJyJHBvYl9wb2JyZSkgKiAxMDAsIGRpZ2l0cyA9IDEpYCUqKiBvZiBwb29yIHBlcnNvbnMgaGF2ZSBiZWVuIHJlYWNoZWQgY291bnRyeXdpZGUuIA0KDQpXaGlsc3QgdGhlcmUgYXJlIG1hbnkgcG9vciBwZXJzb25zIHlldCB0byBiZSByZWFjaGVkIGluIHN0YXRlcyB3aGVyZSB3ZSBoYXZlIHJlbGF0aXZlbHkgaGlnaCBjb3ZlcmFnZSwgdGhlcmUgaXMgYSBuZWVkIHRvIGVuc3VyZSB0aGF0IG91ciBvcGVyYXRpb25hbCBmb290cHJpbnQgYW5kIHRoZSBjb25zZXF1ZW50IHJlc291cmNlcyBhbGxvY2F0ZWQgYXJlIGVxdWl0YWJsZSAtLSB0aGUgY3Jpc2lzIGluIFZlbmV6dWVsYSBpcyBuYXRpb253aWRlIGFuZCB1bmxpa2UgYW4gZWFydGhxdWFrZSBvciBhIHR5cGhvb24gd2hlcmUgdGhlcmUgaXMgYW4gZXBpY2VudHJlIG9yIGEgc3Rvcm1wYXRoLCB0aGVyZSBpcyBubyBwcm9ncmFtbWF0aWMgcmF0aW9uYWxlIHRvIG9ubHkgZm9jdXMgb24gYSBmZXcgYXJlYXMuIA0KDQpMZXQgdXMgbm93IG1vdmUgZG93biB0byBhIGxvd2VyIGxldmVsIG9mIGdyYW51bGFyaXR5IGFzIHN0YXRlLWxldmVsIGFuYWx5c2lzIGlzIHN0aWxsIHF1aXRlIHN1cGVyZmljaWFsOiANCg0KPGJyPg0KDQojIyMgM2IuIFNjYXR0ZXJwbG90IG9mIGdhcHMgYnkgcGFycmlzaCANCg0KRnJvbSB0aGUgc2NhdHRlcnBsb3QgYmVsb3cgLS0gd2hlcmUgZWFjaCBwb2ludCBpcyBhIHBhcnJpc2ggLS0gd2Ugc2VlIHRoYXQgdGhlcmUgaXMgZ3JlYXQgdmFyaWF0aW9uIGluIHRoZSBudW1iZXIgb2YgcG9vciBwZXJzb25zIG5vdCBjb3ZlcmVkIChzaXplKSBhcyB3ZWxsIGFzIGhvdyBjb25jZW50cmF0ZWQgdGhleSBhcmUgaW4gYSBnaXZlbiBwYXJyaXNoICh5LWF4aXMsIHBvdmVydHkgaW5jaWRlbmNlKTsgYm90aCB0aGVzZSBmYWN0b3JzIHdlaWdoIGhlYXZpbHkgaW4gcHJvZ3JhbW1pbmcgc3RyYXRlZ2llcyBhcyB3ZWxsIGFzIGluIHRoZSBlYXNlIG9mIGJlbmVmaWNpYXJ5IHNlbGVjdGlvbi4gIA0KDQpXZSBhbHNvIG9ic2VydmUgdGhhdCB0aGUgcGFycmlzaGVzIHdpdGggdGhlIGdyZWF0ZXN0IG51bWJlcnMgb2Ygbm90IGNvdmVyZWQgKGZvdW5kIGF0IF9wb29yIHBlcnNvbnM6XyAxMCwwMDAtMTAwLDAwMDsgX3BvdmVydHkgaW5jaWRlbmNlOl8gMC4yNS0wLjUwKSBoYXZlIGEgbXVjaCBoaWdoZXIgdGhhbiBhdmVyYWdlIG51bWJlciBvZiBvcmdhbmlzYXRpb25zIHByZXNlbnQgKGNvbG91cikuIFRoaXMgbWVhbnMgdGhhdCBvcGVyYXRpb25hbCBiYXJyaWVycyBhcmUgbXVjaCBsb3dlciBpbiBhY2Nlc3NpbmcgdGhlc2UgcG9wdWxhdGlvbnMgdGhhbiB0aGUgcGFycmlzaGVzIGluIGxpZ2h0IGJsdWUgZm91bmQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgcGxvdC4NCg0KYGBge3IgcGFycnBsb3QtUExPVExZLCBmaWcuaGVpZ2h0PTV9DQoNCnBhcnJwbG90IDwtIHBhcnIwICU+JSANCiAgbXV0YXRlX2F0KHZhcnMocG9iX3BvYnJlLCBub3RfcmVhY2hlZCwgb3JnX2NvdW50KSwgfihyb3VuZCguKSkpICU+JSANCiAgbXV0YXRlKHBlcmNlbnRfcG9icmUgPSByb3VuZChwZXJjZW50X3BvYnJlLCBkaWdpdHMgPSAyKSklPiUgDQogIGdncGxvdChhZXMoeCA9IG5vdF9yZWFjaGVkLCB5ID0gcGVyY2VudF9wb2JyZSwgDQogICAgICAgICAgICAgY29sb3VyID0gb3JnX2NvdW50LCANCiAgICAgICAgICAgICB0ZXh0ID0gcGFzdGUwKHBhcnJvcXVpYSwgIiwgIiwgZXN0YWRvKSkpICsNCiAgZ2VvbV9qaXR0ZXIoYWVzKHNpemUgPSBub3RfcmVhY2hlZCksIGFscGhhID0gMC43NSkgKw0KICBzY2FsZV9jb2xvdXJfZ3JhZGllbnRuKA0KICAgIGNvbG91cnMgPSBjKCJjb3JuZmxvd2VyYmx1ZSIsICJ0b21hdG8iLCAiZmlyZWJyaWNrIikpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwgbGFiZWxzID0gY29tbWEpICsgDQogIHNjYWxlX3NpemVfY29udGludW91cyhyYW5nZSA9IGMoMC4zLCA1KSkgKw0KICB4bGFiKCJOb3QgY292ZXJlZCBwb29yIikgKyB5bGFiKCJQb3ZlcnR5IGluY2lkZW5jZSIpICsNCiAgbGFicyhjb2xvdXIgPSAiTnVtYmVyIG9mIFxub3JnYW5pc2F0aW9ucyIsIA0KICAgICAgIHRpdGxlID0gIlNjYXR0ZXJwbG90IG9mIHBhcnJpc2hlcyBieSBwb29yIHBlcnNvbnMgbm90IGNvdmVyZWQgYW5kIHBvdmVydHkgaW5jaWRlbmNlIikgKw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOC41KSkNCiAgDQoNCmdncGxvdGx5KHBhcnJwbG90LCB0b29sdGlwID0gYygieSIsICJ4IiwgInNpemUiLCAidGV4dCIsICJjb2xvdXIiKSkgJT4lIA0KICAgICAgICAgICBsYXlvdXQoc2hvd2xlZ2VuZCA9IFRSVUUsIGxlZ2VuZCA9IGxpc3QoZm9udCA9IGxpc3Qoc2l6ZSA9IDcpKSkgJT4lDQogICAgICAgICAgIGNvbmZpZyhkaXNwbGF5TW9kZUJhciA9IEZBTFNFKSAlPiUgDQogIGxheW91dCh0aXRsZSA9IGxpc3QodGV4dCA9IHBhc3RlMCgNCiAgICAiU2NhdHRlcnBsb3Qgb2YgcGFycmlzaGVzIGJ5IG51bWJlciBwb29yIHBlcnNvbnMgbm90IHJlYWNoZWQgYW5kIHBvdmVydHkgaW5jaWRlbmNlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8c3VwPiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2l6ZTogbnVtYmVyIG9mIHBvb3IgcGVyc29ucyBub3QgcmVhY2hlZDsgY29sb3VyOiBudW1iZXIgb2Ygb3JnYW5pc2F0aW9ucyBwcmVzZW50OyBkcmFnIGFuZCBjbGljayB0byBzZWxlY3QgYW5kIHpvb20iLCI8L3N1cD4iKSkpDQoNCmBgYA0KDQo8YnI+IA0KDQojIyA0LiBNdWx0aS1zZWN0b3IgcHJvZ3JhbW1pbmcNCg0KSnVzdCBiZWNhdXNlIHR3byBDbHVzdGVycyBvcGVyYXRlIGluIHRoZSBzYW1lIGFyZWEgZG8gbm90IG1lYW4gdGhlaXIgYmVuZWZpY2lhcmllcyBjb2luY2lkZS4gQXMgYW4gZXN0aW1hdGUsIHdlIGNhbGN1bGF0ZWQgYSB0aGVvcmV0aWNhbCBtYXhpbXVtIG51bWJlciBvZiBtdWx0aS1zZWN0b3IgYmVuZWZpY2lhcmllcyBwZXIgcGFycmlzaCwgZXhwcmVzc2VkIGJlbG93IGFzIGBtdWx0aV9zZWN0b3JfYmVuYCAoZXhhY3QgY2FsY3VsYXRpb24gYW5kIGV4cGxhbmF0aW9uIGluIHRoZSBjb2RlIGNodW5rIGJlbG93KS4gUGFycmlzaGVzIGhhdmUgdGhlbiBiZWVuIHNwbGl0IGludG8gZ3JvdXBzIGJhc2VkIG9uIHRoZSBudW1iZXIgb2Ygc2VjdG9ycyBwcmVzZW50IHdpdGhpbiB0aGVtOiAgDQoNCiMjIyA0YS4gU3VtbWFyeSB0YWJsZSBvZiBtdWx0aS1zZWN0b3IgY292ZXJhZ2UgDQoNCmBgYHtyIG11bHRpLXNlY3Rvci1iZW4tVEFCTEUtYW5kLVJFRn0NCiMgY2FsY3VsYXRpb24gZm9yIG11bHRpLXNlY3RvciBiZW5lZmljaWFyaWVzLiANCiMgQmFzaWNhbGx5LCBiZW5lZmljaWFyaWVzIHBlciBwYXJyaXNoIGFyZSBhZ2dyZWdhdGVkIGludG8gDQojIHNlY3RvciBzdWJ0b3RhbHMgYW5kIGEgYmVuZWZpY2lhcnkgZnJlcXVlbmN5IHRvdGFsLiAgDQojIFRoZSBtYXhpbXVtIHZhbHVlIG9mIHRoZSBzZWN0b3Igc3VidG90YWxzIGlzIGNvbXBhcmVkIGFnYWluc3QgdGhlIGJlbmVmaWNpYXJ5IGZyZXF1ZW5jeSB0b3RhbCwgDQojIGlmIHRoZSBtYXhpbXVtIHZhbHVlIGlzIGVxdWFsIHRvIHRoZSBmcmVxdWVuY3kgdG90YWwsIHRoZW4gdGhlcmUgaXMgb25seSBvbmUgc2VjdG9yLA0KIyBpZiB0aGUgbWF4aW11bSB2YWx1ZSBpcyBsZXNzIHRoYW4gdGhlIGZyZXF1ZW5jeSB0b3RhbCwgDQojIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3byAob3IgdGhlIHN1bSBvZiBhbGwgb3RoZXIgc2VjdG9yIHN1YnRvdGFscykgDQojIGJlY29tZXMgdGhlIHRoZW9yZXRpY2FsIG1heGltdW0gbnVtYmVyIG9mIG11bHRpc2VjdG9yIGJlbmVmaWNpYXJpZXMuDQoNCiMgUGVyZm9ybWluZyB0aGlzIGNhbGN1bGF0aW9uIGF0IGFkbWluIGxldmVsIDMgbWFrZXMgc2Vuc2UgYXMgYSBwYXJyaXNoIGlzIHNtYWxsIGVub3VnaA0KIyB0aGF0IHRoZXJlIGl0IGlzIHJlYWxpc3RpYyB0byBhc3N1bWUgdGhhdCBvdmVybGFwcyBpbiBiZW5lZmljaWFyaWVzIGJldHdlZW4gc2VjdG9ycyBleGlzdCAtLQ0KIyBpLmUuIHRoYXQgZmVtYWxlcyB1bmRlciAxOCBpbiBhIHBhcnJpc2ggd2hvIGFyZSBiZW5lZmljaWFyaWVzIG9mIG51dHJpdGlvbiANCiMgYW5kIGZlbWFsZXMgdW5kZXIgMTggaW4gdGhhdCBzYW1lIHBhcnJpc2ggd2hvIGFyZSBiZW5lZmljaWFyaWVzIG9mIFdBU0ggYXJlIHRoZSBzYW1lIHBlb3BsZS4gDQoNCiMgQWx0aG91Z2ggSSBkbyBmZWVsIHRoaXMgY2FsY3VsYXRpb24gdG8gYmUgdmVyeSBjaGFyaXRhYmxlIA0KIyBXZSBjYW4ndCByZWFsbHkgZG8gbXVjaCBtb3JlIHVubGVzcyB0aGVyZSBpcyBhIGJlbmVmaWNpYXJ5IHJlZ2lzdGVyLiANCiMgVGhlIHJlYWwgbnVtYmVyIG9mIG11bHRpc2VjdG9yIGJlbmVmaWNpYXJpZXMgaXMgbGlrZWx5IE1VQ0ggTE9XRVIgDQojIGJ1dCB0aGF0IGNhbiBvbmx5IGJlIHZlcmlmaWVkIHRocm91Z2ggc2FtcGxlZCBsYXJnZS1zY2FsZSBwb3N0LWRpc3RyaWJ1dGlvbi9wb3N0LWludGVydmVudGlvbiBtb25pdG9yaW5nLA0KIyB3aGljaCBpcyBleHRyZW1lbHkgcmFyZS4gDQojIEkgYWN0dWFsbHkgY291bGQgaGF2ZSByYWlzZWQgdGhpcyB3aXRoIHRoZSB0aGlyZC1wYXJ0eSBtb25pdG9ycyB0aGF0IFVOSUNFRiwgDQojIHNvIGl0J3MgYW4gb3ZlcnNpZ2h0IG9uIG15IHBhcnQgYXMgd2VsbC4NCg0KIGFjdF9iZW4gJT4lDQogICMgdmFjY2luYXRpb24gZmlsdGVyZWQgb3V0ICANCiAgIGZpbHRlcihjYXRlZ29yaWFkZWFjdGl2aWRhZCAhPSAiVmFjdW5hY2lvbiIpICU+JSANCiAgICAgICAgICAgICBncm91cF9ieSh1YmljYWNpb24sIGRlc2FncmVnYWNpb24sIHNlY3RvcikgJT4lIA0KICAgICAgICAgICAgICAgICBzbGljZSh3aGljaC5tYXgoYmVuZWZpY2lhcmlvcykpICU+JSANCiAgICAgICAgICAgICAgICAgdW5ncm91cCgpICU+JQ0KICAgICAgICAgICAgICAgICBncm91cF9ieSh1YmljYWNpb24sIHNlY3RvciwgcGNvZGUzKSAlPiUgDQogICAgICAgICAgICAgICAgIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzZWN0b3IsIHZhbHVlc19mcm9tID0gYmVuZWZpY2lhcmlvcykgJT4lIA0KICAgICAgICAgICAgICAgICByZXBsYWNlX25hKGxpc3QoTnV0cmljaW9uID0gMCwgRWR1Y2FjaW9uID0gMCwgV0FTSCA9IDAsIFNhbHVkID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNlZ3VyaWRhZF9BbGltZW50YXJpYSA9IDAsIFByb3RlY2Npb25fTk5BID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb3RlY2Npb25fR2VuZXJhbCA9IDAsIFByb3RlY2Npb25fR0JWID0gMCkpICU+JQ0KICAgICAgICAgICAgIGdyb3VwX2J5KHBjb2RlMywgZGVzYWdyZWdhY2lvbikgJT4lIA0KICAgICAgICAgICAgIHN1bW1hcmlzZShudXRyaWNpb25fYmVuICAgPSBzdW0oTnV0cmljaW9uKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcHJvdGVjY2lvbl9iZW4gID0gc3VtKFByb3RlY2Npb25fTk5BICsgUHJvdGVjY2lvbl9HZW5lcmFsICsgUHJvdGVjY2lvbl9HQlYpLA0KICAgICAgICAgICAgICAgICAgICAgICB3YXNoX2JlbiAgICAgICAgPSBzdW0oV0FTSCksDQogICAgICAgICAgICAgICAgICAgICAgIHNhbHVkX2JlbiAgICAgICA9IHN1bShTYWx1ZCksDQogICAgICAgICAgICAgICAgICAgICAgIGVkdWNhY2lvbl9iZW4gICA9IHN1bShFZHVjYWNpb24pLA0KICAgICAgICAgICAgICAgICAgICAgICBzYV9iZW4gICAgICAgICAgPSBzdW0oU2VndXJpZGFkX0FsaW1lbnRhcmlhKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lIA0KICAgICAgICAgICAgIG11dGF0ZShiZW5fZnJlcSAgID0gbnV0cmljaW9uX2JlbiArIHByb3RlY2Npb25fYmVuICsgd2FzaF9iZW4gKyBzYWx1ZF9iZW4gKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWR1Y2FjaW9uX2JlbiArIHNhX2JlbiwNCiAgICAgICAgICAgICAgICAgICAgYmVuX21heCAgICA9IHBtYXgobnV0cmljaW9uX2JlbiwgcHJvdGVjY2lvbl9iZW4sIHdhc2hfYmVuLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FsdWRfYmVuLCBlZHVjYWNpb25fYmVuLCBzYV9iZW4pLA0KICAgICAgICAgICAgICAgICAgICBtc19iZW5fbWF4ID0gaWZlbHNlKGJlbl9tYXggPj0gYmVuX2ZyZXEgLSBiZW5fbWF4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZW5fZnJlcSAtIGJlbl9tYXgsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlbl9tYXgpKSAlPiUgDQogICAgICAgICAgICAgZ3JvdXBfYnkocGNvZGUzKSAlPiUgDQogICAgICAgICAgICAgc3VtbWFyaXNlKG51dHJpY2lvbl9iZW4gID0gc3VtKG51dHJpY2lvbl9iZW4pLA0KICAgICAgICAgICAgICAgICAgICAgICBwcm90ZWNjaW9uX2JlbiA9IHN1bShwcm90ZWNjaW9uX2JlbiksDQogICAgICAgICAgICAgICAgICAgICAgIHdhc2hfYmVuICAgICAgID0gc3VtKHdhc2hfYmVuKSwNCiAgICAgICAgICAgICAgICAgICAgICAgc2FsdWRfYmVuICAgICAgPSBzdW0oc2FsdWRfYmVuKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZWR1Y2FjaW9uX2JlbiAgPSBzdW0oZWR1Y2FjaW9uX2JlbiksDQogICAgICAgICAgICAgICAgICAgICAgIHNhX2JlbiAgICAgICAgID0gc3VtKHNhX2JlbiksDQogICAgICAgICAgICAgICAgICAgICAgIGJlbl9mcmVxICAgPSBzdW0oYmVuX2ZyZXEpLA0KICAgICAgICAgICAgICAgICAgICAgICBiZW5fbWF4ICAgID0gc3VtKGJlbl9tYXgpLA0KICAgICAgICAgICAgICAgICAgICAgICBtc19iZW5fbWF4ID0gc3VtKG1zX2Jlbl9tYXgpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgDQogICAgICAgICAgICAgbXV0YXRlKHNlY3Rvcl9jb3VudCA9IHJvd1N1bXMoc2VsZWN0KC4sIGVuZHNfd2l0aCgiX2JlbiIpKSAhPSAwKSkgJT4lIA0KICBncm91cF9ieShzZWN0b3JfY291bnQpICU+JSANCiAgIyBmaWx0ZXJpbmcgb3V0IHRoZSBwYXJyaXNoZXMgd2l0aCBvdmVyc3Vic2NyaXB0aW9uIA0KICBmaWx0ZXIocGNvZGUzICVvdXQlIGMoIlZFMDEwMTAxIiwgIlZFMDcwMTA0IiwgIlZFMDcwNTAyIiwgIlZFMDcwNTA2IiwgIlZFMDgxNDAxIiwgIlZFMTAwNDAxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJWRTE1MDcwMSIsICJWRTE1MTkwMSIsICJWRTE1MTkwNSIsICJWRTIwMDEwMSIsICJWRTIwMDQwMyIpKSAlPiUgDQogIHN1bW1hcmlzZShwYXJyb3F1aWFzID0gbigpLA0KICAgICAgICAgICAgbXVsdGlfc2VjdG9yX2JlbiA9IHN1bShtc19iZW5fbWF4KSwNCiAgICAgICAgICAgIG9uZV9zZWN0b3JfYmVuID0gc3VtKGJlbl9mcmVxKSAtIHN1bShtc19iZW5fbWF4KSwgDQogICAgICAgICAgICBtdWx0aXNlY3Rvcl9wZXJjZW50ID0gcm91bmQoc3VtKG1zX2Jlbl9tYXgpIC8gc3VtKGJlbl9mcmVxKSAqIDEwMCwgZGlnaXRzID0gMiksDQogICAgICAgICAgICAuZ3JvdXBzID0gImRyb3AiKSAlPiUgDQogIHJlbG9jYXRlKG11bHRpc2VjdG9yX3BlcmNlbnQsIC5hZnRlciA9IG9uZV9zZWN0b3JfYmVuKSAlPiUgDQogIHBhbmRlcigpDQoNCmBgYA0KDQpPdmVyYWxsLCB0aGUgcmVzdWx0cyBhcmUgbm90IGVuY291cmFnaW5nIC0tIG9ubHkgKipgciByb3VuZChzdW0ocGFycjAkbXNfYmVuX21heCkgLyBzdW0ocGFycjAkYmVuX2ZyZXEpICogMTAwLCBkaWdpdHMgPSAxKWAlKiogb2YgYWxsIGJlbmVmaWNpYXJpZXMgaGF2ZSByZWNlaXZlZCBtdWx0aS1zZWN0b3Igc3VwcG9ydC4gV2hlbiB2YWNjaW5hdGlvbnMgYXJlIGluY2x1ZGVkLCB0aGUgcGVyY2VudGFnZSBkcm9wcyB0byAqKjguNyUqKi4gQnV0IHdlIHdpbGwgZXhjbHVkZSB2YWNjaW5hdGlvbnMgZm9yIHRoaXMgYW5hbHlzaXMgYXMgdGhlaXIgZm9vdHByaW50IGlzIGRldGVybWluZWQgYnkgZ292ZXJubWVudCBwcmlvcml0aWVzLCB3aGljaCBtYXkgb3IgbWF5IG5vdCBhbGlnbiB3aXRoIHRoZSBodW1hbml0YXJpYW4gaW1wZXJhdGl2ZTsgZnVydGhlcm1vcmUsIHRoZSBnb3Zlcm5tZW50IHdhcyBub3QgYWJsZSB0byBwcm92aWRlIHZhY2NpbmF0aW9uIHJlY29yZHMgYXQgdGhlIHBhcnJpc2ggbGV2ZWwsIG1hbnkgdGltZXMgZGVmYXVsdGluZyB0byBtdW5pY2lwYWwgb3Igc3RhdGUtbGV2ZWwgcmVwb3J0aW5nLiANCg0KQXMgYSBub3RlIG51bWJlciBvZiBvcmdhbmlzYXRpb25zIHByZXNlbnQgaW4gYSBwYXJyaXNoIGlzIGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggdGhlIG51bWJlciBvZiBzZWN0b3JzIHByZXNlbnQgdGhlcmUgKGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQgb2YgYHIgcm91bmQoY29yKHBhcnIwJG9yZ19jb3VudCwgcGFycjAkc2VjdG9yX2NvdW50LCBtZXRob2QgPSBjKCJwZWFyc29uIikpLCBkaWdpdHMgPSAzKWApLiBBIHNjYXR0ZXJwbG90IHdvdWxkIGJlIHJlcGV0aXRpdmUgYW5kIHZlcnkgc2ltaWxhciB0byB0aGUgb25lIGluIHNlY3Rpb24gM2IgYW5kIG5vdCBkZWVwZW4gb3VyIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGFjdHVhbCBjb3ZlcmFnZS4gDQoNCjxicj4NCg0KIyMjIDRiLiBTdGF0ZS1sZXZlbCBnYXBzIGluIG11bHRpLXNlY3RvciBwcm9ncmFtbWluZw0KDQpIb3dldmVyLCBmb3IgYWdlbmNpZXMgdHJ1bHkgdW5hYmxlIHRvIGV4cGFuZCBvdXRzaWRlIHRoZWlyIGN1cnJlbnQgZm9vdHByaW50cywgdGhlcmUgYXJlIHN0aWxsIG1hbnkgYmVuZWZpY2lhaXJlcyB3aG8gYXJlIG5vdCBjb3ZlcmVkIG9yIGhhdmUgb25seSBiZWVuIHJlYWNoZWQgd2l0aCB0aGUgaW50ZXJ2ZW50aW9ucyBvZiBvbmUgc2VjdG9yLiANCg0KYGBge3IgbXMtc3RhdGUtc2NhdHRlci1QTE9ULCBmaWcuaGVpZ2h0PTV9DQptc19zY2F0dGVyIDwtIHBhcnIwICU+JSANCiAgZ3JvdXBfYnkoZXN0YWRvKSAlPiUgDQogIHN1bW1hcmlzZShtdWx0aV9zZWN0b3JfYmVuID0gc3VtKG1zX2Jlbl9tYXgpLA0KICAgICAgICAgICAgb25lX3NlY3Rvcl9iZW4gPSByb3VuZChzdW0oYmVuX2ZyZXEpIC0gc3VtKG1zX2Jlbl9tYXgpLCBkaWdpdHMgPSAwKSwNCiAgICAgICAgICAgIGJlbl9mcmVxID0gcm91bmQoc3VtKGJlbl9mcmVxKSwgZGlnaXRzID0gMCkpICU+JSANCiAgbXV0YXRlKG11bHRpc2VjdG9yX3BlcmNlbnQgPSByb3VuZChtdWx0aV9zZWN0b3JfYmVuIC8gYmVuX2ZyZXEgKiAxMDAsIGRpZ2l0cyA9IDEpKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGJlbl9mcmVxLCANCiAgICAgICAgICAgICB5ID0gbXVsdGlzZWN0b3JfcGVyY2VudCkpICsNCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IG9uZV9zZWN0b3JfYmVuKSwgDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgsIGNvbG91ciA9ICJjb3JhbCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGVzdGFkbyksIHNpemUgPSAxLjUpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwgbGFiZWxzID0gY29tbWEpICsNCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygwLjMsIDEwKSkgKw0KICB4bGFiKCJCZW5lZmljaWFyeSBmcmVxdWVuY2llcyIpICsgeWxhYigiUGVyY2VudGFnZSByZWNlaXZlZCBtdWx0aS1zZWN0b3Igc3VwcG9ydCIpICsNCiAgbGFicyh0aXRsZSA9ICJTY2F0dGVycGxvdCBvZiBzdGF0ZXMgYnkgYmVuZWZpY2lhcnkgZnJlcXVlbmNpZXMgYW5kIG11bHRpLXNlY3RvciBjb3ZlcmFnZSBvZiBiZW5lZmljaWFyaWVzIikrDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOC41KSkNCg0KZ2dwbG90bHkobXNfc2NhdHRlciwgdG9vbHRpcCA9IGMoIngiLCAieSIsICJ0ZXh0IiwgInNpemUiKSkgJT4lIA0KICBsYXlvdXQobGVnZW5kID0gbGlzdChmb250ID0gbGlzdChzaXplID0gNikpKSAlPiUgDQogIGNvbmZpZyhkaXNwbGF5TW9kZUJhciA9IEZBTFNFKSAlPiUgDQogIGxheW91dCh0aXRsZSA9IGxpc3QodGV4dCA9IHBhc3RlMCgNCiAgICAiU2NhdHRlcnBsb3Qgb2Ygc3RhdGVzIGJ5IGJlbmVmaWNpYXJ5IGZyZXF1ZW5jaWVzIGFuZCBtdWx0aS1zZWN0b3IgY292ZXJhZ2Ugb2YgYmVuZWZpY2lhcmllcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPHN1cD4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNpemU6IGJlbmVmaWNpYXJpZXMgd2hvIG9ubHkgcmVjZWl2ZWQgc3VwcG9ydCBmcm9tIG9uZSBzZWN0b3I7IG1vdXNlIG92ZXIgZm9yIGRldGFpbHMiLCI8L3N1cD4iKSkpDQpgYGANCg0KDQpBcyB0aGUgbGVhZGVyIG9mIHRoZSBFZHVjYXRpb24sIE51dHJpdGlvbiwgV0FTSCBhbmQgQ2hpbGQgUHJvdGVjdGlvbiBDbHVzdGVycywgVU5JQ0VGIHN1cHBvcnRlZCBhY3Rpdml0aWVzIHJlYWNoaW5nICoqYHIgcm91bmQoKGZpbHRlcihhY3RfYmVuLCBvcmdfbGlkZXIgPT0gIlVOSUNFRiIpICU+JSB7c3VtKC4kYmVuZWZpY2lhcmlvcyl9KSAvIHN1bShhY3RfYmVuJGJlbmVmaWNpYXJpb3MpICogMTAwLCBkaWdpdHMgPSAwKWAlKiogb2YgYWxsIGJlbmVmaWNpYXJpZXMuIE1lYW5pbmcgdGhhdCB0aGlzIHRoZSBsb3cgcGVyY2VudGFnZSBvZiBtdWx0aS1zZWN0b3Igc3VwcG9ydCBjb3VsZCBiZSByZXNvbHZlZCBhbG1vc3QgZW50aXJlbHkgYnkgYmV0dGVyIGludGVyLXNlY3Rpb24gY29vcmRpbmF0aW9uIGFuZCBiZXR0ZXIgcHJvZ3JhbW1hdGljIG92ZXJzaWdodCB3aXRoaW4gVU5JQ0VGLiBJbiBmYWN0LCB3ZSBub3RlIHRoZSBzZWVkcyBvZiB0aGlzIGJlaGF2aW91ciBieSB0aGUgaGlnaGVyIHJhdGVzIG9mIG11bHRpLXNlY3RvciBjb3ZlcmFnZSBpbiB0aGUgc3RhdGVzIHdoZXJlIFVOSUNFRiBoYXMgb2ZmaWNlcyAoQm9saXZhciwgVGFjaGlyYSwgWnVsaWEgYW5kIERpc3RyaXRvIENhcGl0YWwpLiANCg0KQWRkaXRpb25hbGx5LCAqKmByIHJvdW5kKGZpbHRlcihwYXJyLCBlc3RhZG8gJWluJSBjKCJESVNUUklUTyBDQVBJVEFMIiwgIk1JUkFOREEiLCAiWlVMSUEiLCAiVEFDSElSQSIsICJCT0xJVkFSIikpICU+JSB7c3VtKC4kYmVuZWZpY2lhcmlvcyl9IC8gc3VtKHBhcnIkYmVuZWZpY2lhcmlvcykgKiAxMDAsIGRpZ2l0cyA9IDApYCUqKiBvZiBhbGwgYmVuZWZpY2lhcmllcyBhcmUgZnJvbSB0aGUgc3RhdGVzIG9mIERpc3RyaXRvIENhcGl0YWwsIE1pcmFuZGEsIFRhY2hpcmEsIEJvbGl2YXIgYW5kIFp1bGlhLCBpbmRpY2F0aW5nIHRoYXQgdGhlcmUgaXMgc2lnbmlmaWNhbnQgY29udmVyZ2VuY2UgaW4gdGhlIGdlb2dyYXBoaWNhbCByZWFjaGVzIG9mIGluZGl2aWR1YWwgaW1wbGVtZW50aW5nIHBhcnRuZXJzLiANCg0KRm9yIHRob3NlIGxvb2tpbmcgZm9yIHNwZWNpZmljIHBhcnJpc2hlcywgdGhlcmUgaXMgYSByZWZlcmVuY2UgdGFibGUgYXQgdGhlIGVuZCBvZiB0aGlzIGRvY3VtZW50LiAgDQoNCjxicj4NCg0KIyMjIDRjLiBDbHVzdGVyIGNvbWJpbmF0aW9ucw0KDQpCZWZvcmUgd2UgZXhhbWluZSBlYWNoIGNsdXN0ZXIgaW4gbW9yZSBkZXRhaWwsIGhlcmUgaXMgZmlyc3QgYW4gb3ZlcnZpZXcgb2YgdGhlIGdlb2dyYXBoaWMgcmVhY2ggb2YgZWFjaCBjbHVzdGVyOiANCg0KYGBge3IgY2x1c3QtVEFCTEV9DQphY3RfYmVuICU+JSANCiAgZmlsdGVyKHNlY3RvciAhPSAiU2VndXJpZGFkX0FsaW1lbnRhcmlhIiAmIGNhdGVnb3JpYSAhPSAiVkFDVU5BQ0lPTiIpICU+JSANCiAgbXV0YXRlKHNlY3RvciA9IGlmZWxzZShzdHJfZGV0ZWN0KHNlY3RvciwgIlByb3RlY2Npb25fR0JWfFByb3RlY2Npb25fR2VuZXJhbHxQcm90ZWNjaW9uX05OQSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAiUHJvdGVjY2lvbiIsIHNlY3RvcikpICU+JSANCiAgIyBtdXRhdGUoc2VjdG9yID0gaWZlbHNlKGNhdGVnb3JpYSA9PSAiVkFDVU5BQ0lPTiIsICJWYWN1bmFjaW9uIiwgc2VjdG9yKSkNCiAgIyB3ZSdyZSBub3QgZ29pbmcgdG8gbG9vayBhdCB2YWNjaW5hdGlvbiBpbiB0aGlzIHJlcG9ydCANCiAgZ3JvdXBfYnkoc2VjdG9yKSAlPiUgDQogIHN1bW1hcmlzZShwYXJyaXNoZXMgPSBuX2Rpc3RpbmN0KHBjb2RlMyksDQogICAgICAgICAgICBiZW5lZmljaWFyeV9mcmVxdWVuY2llcyA9IHN1bShiZW5lZmljaWFyaW9zKSkgJT4lIA0KICByZW5hbWUoY2x1c3RlciA9IHNlY3RvcikgJT4lIA0KICBwYW5kZXIoY2FwdGlvbiA9ICJDbHVzdGVyIHN1bW1hcnksIHZhY2NpbmF0aW9uIGV4bHVkZWQiLCBiaWcubWFyayA9ICIsIiwgc3R5bGUgPSAicm1hcmtkb3duIiwgDQogICAgICAgICBqdXN0aWZ5ID0gYygibGVmdCIsICJyaWdodCIsICJyaWdodCIpKQ0KICANCmBgYA0KPGJyPiANCg0KVGhlIGZvbGxvd2luZyB0YWJsZXMgc3VtbWFyaXNlIHRoZSBudW1iZXIgb2YgcGFycmlzaGVzIGFuZCBiZW5lZmljaWFyeSBmcmVxdWVuY2llcyByZWFjaGVkIHRocm91Z2ggdGhlIHZhcmlvdXMgY29tYmluYXRpb25zIG9mIGRpZmZlcmVudCBjbHVzdGVycyAtLSB3ZSB1c2UgZnJlcXVlbmNpZXMgaGVyZSwgYXMgZWFjaCBpbmRpdmlkdWFsIG1pZ2h0IGhhdmUgYmVuZWZpdHRlZCBmcm9tIG11bHRpcGxlIGNvbWJpbmF0aW9ucyBvZiBjbHVzdGVycy4gRWFjaCBzdWJzZWN0aW9uIGxpc3RzIHRoZSBwb3NzaWJsZSBwYWlyaW5ncyBvZiBhIGNsdXN0ZXI6IA0KDQoqIGBjb21iaW5hdGlvbmAgcmVmZXJzIHRvIHRoZSB2YXJpb3VzIGNsdXN0ZXItd2lzZSBwYWlycyB0aGF0IGV4aXN0OyANCiogYHBhcnJpc2hlc2AgaW5kaWNhdGVzIHRoZSBudW1iZXIgb2YgcGFycmlzaGVzIGVhY2ggY29tYmluYXRpb24gaXMgcHJlc2VudCBpbjsgDQoqIGBjbHVzdC1mcmVxYCBzaG93cyB0aGUgbnVtYmVyIG9mIGJlbmVmaWNpYXJ5IGZyZXF1ZW5jaWVzIHJlYWNoZWQgYnkgdGhhdCBjbHVzdGVyIA0KKiBgJV9zdWJ0b3RhbGAgaW5kaWNhdGVzIHRoZSBwZXJjZW50YWdlIGVhY2ggY29tYmluYXRpb24gZm9ybXMgb2YgdGhlIHN1YnRvdGFsIG9mIGNsdXN0ZXIgYmVuZWZpY2lhcnkgZnJlcXVlbmNpZXMNCiogYHBhaXJfc3VtYCBzaG93cyB0aGUgdG90YWwgbnVtYmVyIG9mIGJlbmVmaWNpYXJ5IGZyZXF1ZW5jaWVzIGluIHRoYXQgcGFpciBpLmUuIHRoZSBwYWlyX3N1bSBmb3IgZWR1X251dCB3b3VsZCBiZSB0aGUgc3VtIG9mIGVkdWNhdGlvbiBhbmQgbnV0cml0aW9uIGJlbmVmaWNpYXJpZXMuIA0KKiBgJV9tc19tYXhgIHNob3dzIHRoZSBtYXhpbXVtIHBlcmNlbnRhZ2Ugb2YgbXVsdGlzZWN0b3IgYmVuZWZpY2lhcmllcyBvZiBlYWNoIHBhaXIgaS5lLiBpZiB0aGUgcGFpciBlZHVjYXRpb24tbnV0cml0aW9uIGhhcyAxMCBlZHVjYXRpb24gYmVuZWZpY2lhcmllcyBhbmQgMzAgbnV0cml0aW9uIGJlbmVmaWNpYXJpZXMsIHRoZSBtYXhpbXVtIG51bWJlciBvZiBiZW5lZmljaWFyaWVzIHdoaWNoIHJlY2VpdmVkIHN1cHBvcnQgZnJvbSBib3RoIHNlY3RvcnMgaXMgMTAsIHJlc3VsdGluZyBpbiBhIGAlX21zX21heGAgb2YgMjUlLiBCdXQsIGFzIG1lbnRpb25lZCBpbiB0aGUgbm90ZXMgZm9yIHNlY3Rpb24gNGEsIHRoaXMgaXMgYSB0aGVvcmV0aWNhbCBtYXhpbXVtIGFuZCB0aGUgYWN0dWFsIGxldmVsIG9mIGNvaW5jaWRlbmNlIGlzIGxpa2VseSBtdWNoIGxvd2VyLg0KPGJyPg0KDQpgYGB7ciBjbHVzdC1jb20tUkVGfQ0KIyBjcmVhdGlvbiBvZiByZWZlcmVuY2UgZGYgZm9yIHRoZSBjbHVzdGVyIGNvbWJpbmF0aW9ucyANCmNsdXN0X2NvbSA8LSBwYXJyICU+JSANCiAgZmlsdGVyKGJlbl9mcmVxICE9IDApICU+JSANCiAgc2VsZWN0KHBjb2RlMywgYmVuX2ZyZXEsIGVkdWNhY2lvbl9iZW4sIG51dHJpY2lvbl9iZW4sIHNhbHVkX2Jlbiwgd2FzaF9iZW4sIHByb3RlY2Npb25fYmVuKSAlPiUNCiAgIyBtdXRhdGUgYSBuZXcgY29sdW1uIGZvciBlYWNoIGNvbWJpbmF0aW9uIG9mIHNlY3RvcnMgLS0gaWYgZWR1IGlzIHRoZSBmaXJzdCBjbHVzdGVyIGluIHRoZSBjb21iaW5hdGlvbiwgDQogICMgb25seSBlZHVjYXRpb24gYmVuZWZpY2lhcmllcyB3aWxsIGJlIHVzZWQgdG8gZmlsbCB2YWx1ZXMgaW4gdGhlIGNvbHVtbiANCiAgbXV0YXRlKGVkdV9hbG9uZSA9IGlmZWxzZShlZHVjYWNpb25fYmVuID09IGJlbl9mcmVxLCBlZHVjYWNpb25fYmVuLCAwKSwNCiAgICAgICAgIGVkdV9udXQgPSBpZmVsc2UoZWR1Y2FjaW9uX2JlbiA+IDAgJiBudXRyaWNpb25fYmVuID4gMCwgZWR1Y2FjaW9uX2JlbiwgMCksDQogICAgICAgICBlZHVfc2FsID0gaWZlbHNlKGVkdWNhY2lvbl9iZW4gPiAwICYgc2FsdWRfYmVuID4gMCwgZWR1Y2FjaW9uX2JlbiwgMCksDQogICAgICAgICBlZHVfd2FzaCA9IGlmZWxzZShlZHVjYWNpb25fYmVuID4gMCAmIHdhc2hfYmVuID4gMCwgZWR1Y2FjaW9uX2JlbiwgMCksDQogICAgICAgICBlZHVfcHJvdCA9IGlmZWxzZShlZHVjYWNpb25fYmVuID4gMCAmIHByb3RlY2Npb25fYmVuID4gMCwgZWR1Y2FjaW9uX2JlbiwgMCksDQogICAgICAgICBudXRfYWxvbmUgPSBpZmVsc2UobnV0cmljaW9uX2JlbiA9PSBiZW5fZnJlcSwgbnV0cmljaW9uX2JlbiwgMCksDQogICAgICAgICBudXRfZWR1ID0gaWZlbHNlKGVkdWNhY2lvbl9iZW4gPiAwICYgbnV0cmljaW9uX2JlbiA+IDAsIG51dHJpY2lvbl9iZW4sIDApLA0KICAgICAgICAgbnV0X3NhbCA9IGlmZWxzZShudXRyaWNpb25fYmVuID4gMCAmIHNhbHVkX2JlbiA+IDAsIG51dHJpY2lvbl9iZW4sIDApLCANCiAgICAgICAgIG51dF93YXNoID0gaWZlbHNlKG51dHJpY2lvbl9iZW4gPiAwICYgd2FzaF9iZW4gPiAwLCBudXRyaWNpb25fYmVuLCAwKSwgDQogICAgICAgICBudXRfcHJvdCA9IGlmZWxzZShudXRyaWNpb25fYmVuID4gMCAmIHByb3RlY2Npb25fYmVuID4gMCwgbnV0cmljaW9uX2JlbiwgMCksDQogICAgICAgICBzYWxfYWxvbmUgPSBpZmVsc2Uoc2FsdWRfYmVuID09IGJlbl9mcmVxLCBzYWx1ZF9iZW4sIDApLA0KICAgICAgICAgc2FsX2VkdSA9IGlmZWxzZShlZHVjYWNpb25fYmVuID4gMCAmIHNhbHVkX2JlbiA+IDAsIHNhbHVkX2JlbiwgMCksDQogICAgICAgICBzYWxfbnV0ID0gaWZlbHNlKG51dHJpY2lvbl9iZW4gPiAwICYgc2FsdWRfYmVuID4gMCwgc2FsdWRfYmVuLCAwKSwNCiAgICAgICAgIHNhbF93YXNoID0gaWZlbHNlKHNhbHVkX2JlbiA+IDAgJiB3YXNoX2JlbiA+IDAsIHNhbHVkX2JlbiwgMCksDQogICAgICAgICBzYWxfcHJvdCA9IGlmZWxzZShwcm90ZWNjaW9uX2JlbiA+IDAgJiBzYWx1ZF9iZW4gPiAwLCBzYWx1ZF9iZW4sIDApLA0KICAgICAgICAgd2FzaF9hbG9uZSA9IGlmZWxzZSh3YXNoX2JlbiA9PSBiZW5fZnJlcSwgd2FzaF9iZW4sIDApLA0KICAgICAgICAgd2FzaF9lZHUgPSBpZmVsc2UoZWR1Y2FjaW9uX2JlbiA+IDAgJiB3YXNoX2JlbiA+IDAsIHdhc2hfYmVuLCAwKSwNCiAgICAgICAgIHdhc2hfbnV0ID0gaWZlbHNlKG51dHJpY2lvbl9iZW4gPiAwICYgd2FzaF9iZW4gPiAwLCB3YXNoX2JlbiwgMCksDQogICAgICAgICB3YXNoX3NhbCA9IGlmZWxzZShzYWx1ZF9iZW4gPiAwICYgd2FzaF9iZW4gPiAwLCB3YXNoX2JlbiwgMCksDQogICAgICAgICB3YXNoX3Byb3QgPSBpZmVsc2Uod2FzaF9iZW4gPiAwICYgcHJvdGVjY2lvbl9iZW4gPiAwLCB3YXNoX2JlbiwgMCksDQogICAgICAgICBwcm90X2Fsb25lID0gaWZlbHNlKHByb3RlY2Npb25fYmVuID09IGJlbl9mcmVxLCBwcm90ZWNjaW9uX2JlbiwgMCksIA0KICAgICAgICAgcHJvdF9lZHUgPSBpZmVsc2UoZWR1Y2FjaW9uX2JlbiA+IDAgJiBwcm90ZWNjaW9uX2JlbiA+IDAsIHByb3RlY2Npb25fYmVuLCAwKSwNCiAgICAgICAgIHByb3RfbnV0ID0gaWZlbHNlKG51dHJpY2lvbl9iZW4gPiAwICYgcHJvdGVjY2lvbl9iZW4gPiAwLCBwcm90ZWNjaW9uX2JlbiwgMCksDQogICAgICAgICBwcm90X3NhbCA9IGlmZWxzZShwcm90ZWNjaW9uX2JlbiA+IDAgJiBzYWx1ZF9iZW4gPiAwLCBwcm90ZWNjaW9uX2JlbiwgMCksDQogICAgICAgICBwcm90X3dhc2ggPSBpZmVsc2Uod2FzaF9iZW4gPiAwICYgcHJvdGVjY2lvbl9iZW4gPiAwLCBwcm90ZWNjaW9uX2JlbiwgMCkpICU+JQ0KICAjIHBpdm90X2xvbmdlciB0byB0aGUgY2x1c3RfZnJlcSBjb2x1bW4gDQogIHBpdm90X2xvbmdlcihuYW1lc190byA9ICJjb21iaW5hdGlvbiIsIHZhbHVlc190byA9ICJjbHVzdF9mcmVxIiwgODozMikgJT4lDQogICMgbXV0YXRpbmcgbmV3IGNsdXN0ZXIgY29sdW1uIGZvciBmaWx0ZXJpbmcgbGF0ZXINCiAgbXV0YXRlKGNsdXN0ZXIgPSBjYXNlX3doZW4oc3RyX2RldGVjdChjb21iaW5hdGlvbiwgIl5lZHUiKSB+ICJlZHVjYWNpb24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KGNvbWJpbmF0aW9uLCAiXm51dCIpIH4gIm51dHJpY2lvbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cl9kZXRlY3QoY29tYmluYXRpb24sICJec2FsIikgfiAic2FsdWQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJfZGV0ZWN0KGNvbWJpbmF0aW9uLCAiXndhc2giKSB+ICJ3YXNoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyX2RldGVjdChjb21iaW5hdGlvbiwgIl5wcm90IikgfiAicHJvdGVjY2lvbiIpKSAlPiUNCiAgIyBjYWxjdWxhdGluZyB0aGUgc3VtIG9mIGZyZXF1ZW5jaWVzIGluIGVhY2ggcGFpcg0KICBtdXRhdGUocGFpcl9mcmVxID0gDQogICAgICAgICAgIGNhc2Vfd2hlbigNCiAgICAgICAgICAgICBzdHJfZGV0ZWN0KGNvbWJpbmF0aW9uLCAiZWR1X251dHxudXRfZWR1IikgfiBlZHVjYWNpb25fYmVuICsgbnV0cmljaW9uX2JlbiwNCiAgICAgICAgICAgICBzdHJfZGV0ZWN0KGNvbWJpbmF0aW9uLCAiZWR1X3NhbHxzYWxfZWR1IikgfiBlZHVjYWNpb25fYmVuICsgc2FsdWRfYmVuLA0KICAgICAgICAgICAgIHN0cl9kZXRlY3QoY29tYmluYXRpb24sICJlZHVfd2FzaHx3YXNoX2VkdSIpIH4gZWR1Y2FjaW9uX2JlbiArIHdhc2hfYmVuLA0KICAgICAgICAgICAgIHN0cl9kZXRlY3QoY29tYmluYXRpb24sICJlZHVfcHJvdHxwcm90X2VkdSIpIH4gZWR1Y2FjaW9uX2JlbiArIHByb3RlY2Npb25fYmVuLA0KICAgICAgICAgICAgIHN0cl9kZXRlY3QoY29tYmluYXRpb24sICJudXRfc2FsfHNhbF9udXQiKSB+IG51dHJpY2lvbl9iZW4gKyBzYWx1ZF9iZW4sDQogICAgICAgICAgICAgc3RyX2RldGVjdChjb21iaW5hdGlvbiwgIm51dF93YXNofHdhc2hfbnV0IikgfiBudXRyaWNpb25fYmVuICsgd2FzaF9iZW4sDQogICAgICAgICAgICAgc3RyX2RldGVjdChjb21iaW5hdGlvbiwgIm51dF9wcm90fHByb3RfbnV0IikgfiBudXRyaWNpb25fYmVuICsgcHJvdGVjY2lvbl9iZW4sDQogICAgICAgICAgICAgc3RyX2RldGVjdChjb21iaW5hdGlvbiwgInNhbF93YXNofHdhc2hfc2FsIikgfiBzYWx1ZF9iZW4gKyB3YXNoX2JlbiwNCiAgICAgICAgICAgICBzdHJfZGV0ZWN0KGNvbWJpbmF0aW9uLCAic2FsX3Byb3R8cHJvdF9zYWwiKSB+IHNhbHVkX2JlbiArIHByb3RlY2Npb25fYmVuLA0KICAgICAgICAgICAgIHN0cl9kZXRlY3QoY29tYmluYXRpb24sICJwcm90X3dhc2h8d2FzaF9wcm90IikgfiBwcm90ZWNjaW9uX2JlbiArIHdhc2hfYmVuLA0KICAgICAgICAgICAgIFRSVUUgfiBOQV9yZWFsXykpICU+JSANCiAgbXV0YXRlKHBhaXJfZnJlcSA9IGlmZWxzZShzdHJfZGV0ZWN0KGNvbWJpbmF0aW9uLCAiYWxvbmUkIiksIDAsIHBhaXJfZnJlcSkpICU+JSANCiAgc2VsZWN0KHBjb2RlMywgYmVuX2ZyZXEsIGNvbWJpbmF0aW9uLCBjbHVzdGVyLCBjbHVzdF9mcmVxLCBwYWlyX2ZyZXEpDQoNCmBgYA0KDQpgYGB7ciBjYy1lZHUtVEFCTEV9DQpjbHVzdF9jb20gJT4lIA0KICBmaWx0ZXIoY2x1c3RlciA9PSAiZWR1Y2FjaW9uIiAmIGNsdXN0X2ZyZXEgIT0gMCkgJT4lIA0KICBncm91cF9ieShjb21iaW5hdGlvbikgJT4lIA0KICBzdW1tYXJpc2UocGFycmlzaGVzID0gbigpLA0KICAgICAgICAgICAgY2x1c3RfZnJlcSA9IHN1bShjbHVzdF9mcmVxKSwNCiAgICAgICAgICAgIHBhaXJfc3VtID0gc3VtKHBhaXJfZnJlcSkpICU+JSANCiAgbXV0YXRlKG1zX21heCAgPSByb3VuZChwbWluKGNsdXN0X2ZyZXEsIGFicyhjbHVzdF9mcmVxIC0gcGFpcl9zdW0pKSwgZGlnaXRzID0gMSksDQogICAgICAgICBgJV9tc19tYXhgID0gcm91bmQobXNfbWF4IC8gcGFpcl9zdW0gKiAxMDAsIGRpZ2l0cyA9IDEpLA0KICAgICAgICAgYCVfbXNfbWF4YCA9IGlmZWxzZShpcy5pbmZpbml0ZShgJV9tc19tYXhgKSwgMCwgYCVfbXNfbWF4YCkpICU+JSANCg0KICBwYW5kZXIoY2FwdGlvbiA9ICJFZHVjYXRpb24gY2x1c3RlciBjb21iaW5hdGlvbnMiLCBiaWcubWFyayA9ICIsIiwgc3R5bGUgPSAicm1hcmtkb3duIiwgDQogICAgICAgICBqdXN0aWZ5ID0gYygibGVmdCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIpKQ0KYGBgDQoNClRoZSBtb3N0IGNvbW1vbiBwYWlyaW5nIGZvciBFZHVjYXRpb24gd2FzIHdpdGggdGhlIE51dHJpdGlvbiBjbHVzdGVyIC0tIHRoZXkgY29pbmNpZGUgaW4gYHIgY2x1c3RfY29tICU+JSBmaWx0ZXIoY29tYmluYXRpb24gPT0gImVkdV9udXQiICYgY2x1c3RfZnJlcSAhPSAwKSAlPiUgbnJvdygpYCBwYXJyaXNoZXMuIEhvd2V2ZXIsIHRoZXJlIGFyZSBubyBjb25jcmV0ZSBwcm9ncmFtbWF0aWMgbGlua3MgcHJvZ3JhbW1hdGljYWxseSBiZXR3ZWVuIHRoZSB0d28sIHdpdGggTnV0cml0aW9uIGZvY3VzaW5nIG9uIHBlcnNvbnMgb2xkZXIgb3IgeW91bmdlciB0aGFuIHRoZSBtYWpvcml0eSBvZiBFZHVjYXRpb24ncyBiZW5lZmljaWFyaWVzLiBIb3dldmVyLCBQcm90ZWN0aW9uIGFuZCBXQVNIIGJvdGggaGF2ZSBleHBsaWNpdCBwcm9ncmFtbWF0aWMgbGlua3MgKGluIHRoZSBsb2dmcmFtZSkgd2l0aCBFZHVjYXRpb24gYW5kIGByIGNsdXN0X2NvbSAlPiUgZmlsdGVyKGNvbWJpbmF0aW9uID09ICJlZHVfcHJvdCIgJiBjbHVzdF9mcmVxICE9IDApICU+JSBucm93KClgIGFuZCBgciBjbHVzdF9jb20gJT4lIGZpbHRlcihjb21iaW5hdGlvbiA9PSAiZWR1X3dhc2giICYgY2x1c3RfZnJlcSAhPSAwKSAlPiUgbnJvdygpYCBwYXJyaXNoZXMgcmVzcGVjdGl2ZWx5LiBBIGZydWl0ZnVsIGF2ZW51ZSBvZiBpbnZlc3RpZ2F0aW9uIHdvdWxkIGJlIGhvdyBtYW55IGJlbmVmaWNpYXJpZXMgb2YgRWR1Y2F0aW9uIGFsc28gYmVuZWZpdHRlZCBmcm9tIFByb3RlY3Rpb24gaW50ZXJ2ZW50aW9ucyBhbmQgaG93IGNsb3NlIGl0IGlzIHRvIHRoZSAzNy45JSB0aGVvcmV0aWNhbCBtYXhpbXVtLiANCg0KPGJyPg0KDQpgYGB7ciBjYy1udXRyaXRpb24tVEFCTEV9DQpjbHVzdF9jb20gJT4lIA0KICBmaWx0ZXIoY2x1c3RlciA9PSAibnV0cmljaW9uIiAmIGNsdXN0X2ZyZXEgIT0gMCkgJT4lIA0KICBncm91cF9ieShjb21iaW5hdGlvbikgJT4lIA0KICBzdW1tYXJpc2UocGFycmlzaGVzID0gbigpLA0KICAgICAgICAgICAgY2x1c3RfZnJlcSA9IHN1bShjbHVzdF9mcmVxKSwNCiAgICAgICAgICAgIHBhaXJfc3VtID0gc3VtKHBhaXJfZnJlcSkpICU+JSANCiAgbXV0YXRlKGAlX3N1YnRvdGFsYCA9IHJvdW5kKGNsdXN0X2ZyZXEgLyBzdW0oY2x1c3RfZnJlcSkgKiAxMDAsIGRpZ2l0cyA9IDEpLA0KICAgICAgICAgYCVfbXNfbWF4YCA9IHJvdW5kKHBtaW4oY2x1c3RfZnJlcSwgYWJzKGNsdXN0X2ZyZXEgLSBwYWlyX3N1bSkpIC8gcGFpcl9zdW0gKiAxMDAsIGRpZ2l0cyA9IDEpLA0KICAgICAgICAgYCVfbXNfbWF4YCA9IGlmZWxzZShpcy5pbmZpbml0ZShgJV9tc19tYXhgKSwgMCwgYCVfbXNfbWF4YCkpICU+JSANCiAgICByZWxvY2F0ZShgJV9zdWJ0b3RhbGAsIC5hZnRlciA9IGNsdXN0X2ZyZXEpICU+JSANCg0KICBwYW5kZXIoY2FwdGlvbiA9ICJOdXRyaXRpb24gY2x1c3RlciBjb21iaW5hdGlvbnMiLCBiaWcubWFyayA9ICIsIiwgc3R5bGUgPSAicm1hcmtkb3duIiwgDQogICAgICAgICBqdXN0aWZ5ID0gYygibGVmdCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIpKQ0KYGBgDQoNCk51dHJpdGlvbiBvcGVyYXRlcyBhbG9uZSBpbiAyODIgcGFycmlzaGVzIG91dCBvZiB0aGUgYHIgYWN0X2JlbiAlPiUgZmlsdGVyKHNlY3RvciA9PSAiTnV0cmljaW9uIikgJT4lIGRpc3RpbmN0KHBjb2RlMykgJT4lIG5yb3coKWAgdGhhdCBpdCBvcGVyYXRlcyBpbiwgdGhpcyBpcyB0aGUgbW9zdCBvdXQgb2YgYW55IG9mIHRoZSBvdGhlciBjbHVzdGVycyAtLSBpdCBpcyBuZWNlc3NhcnkgdG8gZXZhbHVhdGUgdGhlIGV4dGVudCB0byB3aGljaCBvdGhlciBjbHVzdGVycyBjYW4gbWFrZSB1c2Ugb2YgdGhlIGZvb3Rob2xkcyBlc3RhYmxpc2hlZCBieSBOdXRyaXRpb24uIEluIHRoaXMgbGlnaHQsIGl0IHNlZW1zIHRoYXQgaXRzIGhpZ2ggbGV2ZWwgb2YgY29pbmNpZGVuY2Ugd2l0aCBFZHVjYXRpb24gd2FzIGR1ZSBtb3JlIHRvIGl0cyB3aWRlIG9wZXJhdGlvbmFsIHByZXNlbmNlIHJhdGhlciB0aGFuIGR1ZSB0byBjb25jZXJ0ZWQgY29vcmRpbmF0aW9uLiBUaGUgaGlnaGVzdCBwb3NzaWJpbGl0eSBvZiBvdmVybGFwIGlzIHdpdGggSGVhbHRoLCBkdWUgdG8gMSkgdGhlaXIgcmVzcGVjdGl2ZSBiZW5lZmljaWFyeSBmcmVxdWVuY2llcyBub3QgZGlmZmVyaW5nIGFzIG11Y2ggYXMgd2l0aCB0aGUgb3RoZXIgY2x1c3RlcnMgYW5kIDIpIHRoZSBudW1lcm91cyBwcm9ncmFtbWF0aWMgbGlua3MgYmV0d2VlbiB0aGUgdHdvLiBIb3dldmVyLCBoYXMgdGhlIGxvd2VzdCBudW1iZXIgb2YgYmVuZWZpY2lhcmllcyBpbiBwYXJyaXNoZXMgd2hlcnJlIGhlYWx0aCBpcyBhbHNvIHByZXNlbnQuIA0KDQo8YnI+DQoNCmBgYHtyIGNjLWhlYWx0aC1UQUJMRX0NCmNsdXN0X2NvbSAlPiUgDQogIGZpbHRlcihjbHVzdGVyID09ICJzYWx1ZCIgJiBjbHVzdF9mcmVxICE9IDApICU+JSANCiAgZ3JvdXBfYnkoY29tYmluYXRpb24pICU+JSANCiAgc3VtbWFyaXNlKHBhcnJpc2hlcyA9IG4oKSwNCiAgICAgICAgICAgIGNsdXN0X2ZyZXEgPSBzdW0oY2x1c3RfZnJlcSksDQogICAgICAgICAgICBwYWlyX3N1bSA9IHN1bShwYWlyX2ZyZXEpKSAlPiUgDQogIG11dGF0ZShgJV9zdWJ0b3RhbGAgPSByb3VuZChjbHVzdF9mcmVxIC8gc3VtKGNsdXN0X2ZyZXEpICogMTAwLCBkaWdpdHMgPSAxKSwNCiAgICAgICAgIGAlX21zX21heGAgPSByb3VuZChwbWluKGNsdXN0X2ZyZXEsIGFicyhjbHVzdF9mcmVxIC0gcGFpcl9zdW0pKSAvIHBhaXJfc3VtICogMTAwLCBkaWdpdHMgPSAxKSwNCiAgICAgICAgIGAlX21zX21heGAgPSBpZmVsc2UoaXMuaW5maW5pdGUoYCVfbXNfbWF4YCksIDAsIGAlX21zX21heGApKSAlPiUgDQogICAgcmVsb2NhdGUoYCVfc3VidG90YWxgLCAuYWZ0ZXIgPSBjbHVzdF9mcmVxKSAlPiUgDQoNCiAgcGFuZGVyKGNhcHRpb24gPSAiSGVhbHRoIGNsdXN0ZXIgY29tYmluYXRpb25zLCBleGNsdWRpbmcgdmFjY2luYXRpb25zIiwgDQogICAgICAgICBiaWcubWFyayA9ICIsIiwgc3R5bGUgPSAicm1hcmtkb3duIiwgDQogICAgICAgICBqdXN0aWZ5ID0gYygibGVmdCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIpKQ0KYGBgDQoNCldpdGhvdXQgdmFjY2luYXRpb24gaW50ZXJ2ZW50aW9ucywgaGVhbHRoIGhhcyB0aGUgc21hbGxlc3QgZm9vdHByaW50IG9mIGFueSBvZiB0aGUgY2x1c3RlcnMsIGNvdmVyaW5nIGByIGFjdF9iZW4gJT4lIGZpbHRlcihzZWN0b3IgPT0gIlNhbHVkIiAmIGNhdGVnb3JpYSAhPSAiVkFDVU5BQ0lPTiIpICU+JSBkaXN0aW5jdChwY29kZTMpICU+JSBucm93KClgIHBhcnJpc2hlcyBhbmQgYHIgYWN0X2JlbiAlPiUgZmlsdGVyKHNlY3RvciA9PSAiU2FsdWQiICYgY2F0ZWdvcmlhICE9ICJWQUNVTkFDSU9OIikgJT4lIHtzdW0oLiRiZW5lZmljaWFyaW9zKX1gIGJlbmVmaWNpYXJ5IGZyZXF1ZW5jaWVzLiBJdCBjb2luY2lkZXMgdGhlIG1vc3Qgd2l0aCBOdXRyaXRpb24gYW5kIFByb3RlY3Rpb24gYW5kIGhhcyBudW1lcm91cyBwcm9ncmFtbWF0aWMgb3Bwb3J0dW5pdGllcyB0byBjb29yZGluYXRlIHdpdGggYm90aCBhdCB0aGUgaW50ZXJ2ZW50aW9uIGxldmVsIHdpdGggaXRzIGZvY3VzIG9uIG9ic3RldHJpYywgYW50ZW5hdGFsIGFuZCBuZW9uYXRhbCBjYXJlIGFzIHdlbGwgYXMgd2l0aCBISVYgZGlhZ25vc2lzIGFuZCB0cmVhdG1lbnQuIA0KDQo8YnI+IA0KDQpgYGB7ciBjYy13YXNoLVRBQkxFfQ0KY2x1c3RfY29tICU+JSANCiAgZmlsdGVyKGNsdXN0ZXIgPT0gIndhc2giICYgY2x1c3RfZnJlcSAhPSAwKSAlPiUgDQogIGdyb3VwX2J5KGNvbWJpbmF0aW9uKSAlPiUgDQogIHN1bW1hcmlzZShwYXJyaXNoZXMgPSBuKCksDQogICAgICAgICAgICBjbHVzdF9mcmVxID0gc3VtKGNsdXN0X2ZyZXEpLA0KICAgICAgICAgICAgcGFpcl9zdW0gPSBzdW0ocGFpcl9mcmVxKSkgJT4lIA0KICBtdXRhdGUoYCVfc3VidG90YWxgID0gcm91bmQoY2x1c3RfZnJlcSAvIHN1bShjbHVzdF9mcmVxKSAqIDEwMCwgZGlnaXRzID0gMSksDQogICAgICAgICBgJV9tc19tYXhgID0gcm91bmQocG1pbihjbHVzdF9mcmVxLCBhYnMoY2x1c3RfZnJlcSAtIHBhaXJfc3VtKSkgLyBwYWlyX3N1bSAqIDEwMCwgZGlnaXRzID0gMSksDQogICAgICAgICBgJV9tc19tYXhgID0gaWZlbHNlKGlzLmluZmluaXRlKGAlX21zX21heGApLCAwLCBgJV9tc19tYXhgKSkgJT4lIA0KICAgIHJlbG9jYXRlKGAlX3N1YnRvdGFsYCwgLmFmdGVyID0gY2x1c3RfZnJlcSkgJT4lIA0KDQogIHBhbmRlcihjYXB0aW9uID0gIldBU0ggY2x1c3RlciBjb21iaW5hdGlvbnMiLCBiaWcubWFyayA9ICIsIiwgc3R5bGUgPSAicm1hcmtkb3duIiwgDQogICAgICAgICBqdXN0aWZ5ID0gYygibGVmdCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIpKQ0KYGBgDQoNCkFsbW9zdCBub25lIG9mIFdBU0gncyBiZW5lZmljaWFyeSBmcmVxdWVuY2llcyBvY2N1cnJlZCBpbiBwYXJyaXNoZXMgd2hlcmUgbm8gb3RoZXIgY2x1c3RlcnMgd2VyZSBwcmVzZW50LiBJdHMgZ3JlYXQgcmVhY2ggYW5kIGJsYW5rZXQgY292ZXJhZ2UgKGVzcGVjaWFsbHkgd2F0ZXIgc3VwcGx5IGFuZCBvdGhlciBjb21tdW5pdHktbGV2ZWwgYWN0aXZpdGllcykgbWVhbiB0aGF0IG90aGVyIGNsdXN0ZXJzIG9wZXJhdGluZyBpbiB0aGUgc2FtZSBhcmVhcyBhcyBXQVNIIGFyZSAiZ3VhcmFudGVlZCIgdG8gcmVhY2ggYmVuZWZpY2lhcmllcyB3aXRoIG11bHRpLXNlY3RvciBwcm9ncmFtbWluZyAtLSB0aGUgY2hhbGxlbmdlcyBiZWluZyAxLiB0aGUgaW50ZW50aW9uYWxpdHkgb2YgdGhlIG11bHRpLXNlY3RvciBjb3ZlcmFnZSBhbmQgMi4gbWF0Y2hpbmcgdGhlIHNjYWxlIG9mIFdBU0ggYWN0aXZpdGllcy4gV0FTSCBoYXMgZXhjZWxsZW50IHByb2dyYW1tYXRpYyBvdmVybGFwIHdpdGggYWxsIG90aGVyIGNsdXN0ZXJzLiANCg0KPGJyPg0KDQpgYGB7ciBjYy1wcm90ZWN0aW9uLVRBQkxFfQ0KY2x1c3RfY29tICU+JSANCiAgZmlsdGVyKGNsdXN0ZXIgPT0gInByb3RlY2Npb24iICYgY2x1c3RfZnJlcSAhPSAwKSAlPiUgDQogIGdyb3VwX2J5KGNvbWJpbmF0aW9uKSAlPiUgDQogIHN1bW1hcmlzZShwYXJyaXNoZXMgPSBuKCksDQogICAgICAgICAgICBjbHVzdF9mcmVxID0gc3VtKGNsdXN0X2ZyZXEpLA0KICAgICAgICAgICAgcGFpcl9zdW0gPSBzdW0ocGFpcl9mcmVxKSkgJT4lIA0KICBtdXRhdGUoYCVfc3VidG90YWxgID0gcm91bmQoY2x1c3RfZnJlcSAvIHN1bShjbHVzdF9mcmVxKSAqIDEwMCwgZGlnaXRzID0gMSksDQogICAgICAgICBgJV9tc19tYXhgID0gcm91bmQocG1pbihjbHVzdF9mcmVxLCBhYnMoY2x1c3RfZnJlcSAtIHBhaXJfc3VtKSkgLyBwYWlyX3N1bSAqIDEwMCwgZGlnaXRzID0gMSksDQogICAgICAgICBgJV9tc19tYXhgID0gaWZlbHNlKGlzLmluZmluaXRlKGAlX21zX21heGApLCAwLCBgJV9tc19tYXhgKSkgJT4lIA0KICAgIHJlbG9jYXRlKGAlX3N1YnRvdGFsYCwgLmFmdGVyID0gY2x1c3RfZnJlcSkgJT4lIA0KDQogIHBhbmRlcihjYXB0aW9uID0gIlByb3RlY3Rpb24gY2x1c3RlciBjb21iaW5hdGlvbnMiLCBiaWcubWFyayA9ICIsIiwgc3R5bGUgPSAicm1hcmtkb3duIiwgDQogICAgICAgICBqdXN0aWZ5ID0gYygibGVmdCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIsICJyaWdodCIpKQ0KYGBgDQoNCkxpa2UgV0FTSCBhbmQgaGVhbHRoLCBQcm90ZWN0aW9uIGhhcyB2ZXJ5IGxpbWl0ZWQgYmVuZWZpY2lhcnkgZnJlcXVlbmNpZXMgaW4gcGFycmlzaGVzIHdoZXJlIGl0IG9wZXJhdGVzIGFsb25lLiBQcm90ZWN0aW9uIGNvaW5jaWRlcyB0aGUgbW9zdCB3aXRoIE51dHJpdGlvbiAtLSB0aGlzIHNob3VsZCBzZXJ2ZSBhcyBhbiBpbXB1bHNlIGZvciB0aGUgY3JlYXRpb24gb2YgcmVmZXJyYWwgcGF0aHdheXMgYmV0d2VlbiB0aGUgdHdvIHNpbmNlIGJvdGggY2Fycnkgb3V0IHNjcmVlbmluZyBhY3Rpdml0aWVzOyBhZGRpdGlvbmFsbHksIGJvdGggbWFuYWdlIHNvbWUgZm9ybSBvZiBiZW5lZmljaWFyeS1sZXZlbCBkYXRhYmFzZS4gVGhpcyBjbHVzdGVyIGhhcyB0aGUgbW9zdCBleHBsaWNpdCBwcm9nYW1tYXRpYyBsaW5rcyB0byBFZHVjYXRpb24uIA0KDQpUbyBjbG9zZSwgdGhlIHN0YXRlIG9mIG11bHRpLXNlY3RvciBwcm9ncmFtbWluZyBpcyBwb29yLiBUaGVyZSBpcyBsaXR0bGUgaW50ZW50aW9uYWxpdHkgaW4gd2hpY2ggYXJlYXMgaGF2ZSBtdWx0aS1zZWN0b3IgY292ZXJhZ2UgYW5kIHdoaWNoIGFyZWFzIGRvIG5vdCAtLSBtdWx0aS1zZWN0b3IgbGlua3MgZG8gZXhpc3QgYXQgdGhlIGFjdGl2aXR5IGxldmVsLCBidXQgdGhpcyBpcyBhIHBvb3IgYXBwcm94aW1hdGlvbiBvZiBkZXZlbG9waW5nIGEgcHJvZ3JhbW1lIGJhc2VkIG9uIHRoZSBzcGVjaWZpYyBuZWVkcyBvZiBhIHRhcmdldCBhcmVhLiBXZSBzZWUgbXVjaCBiZXR0ZXIgbXVsdGktc2VjdG9yIGNvdmVyYWdlIGluIHRoZSBhcmVhcyB3aGVyZSBVTklDRUYgaGFzIG9mZmljZXMsIGluZGljYXRpbmcgdGhhdCBmaWVsZCBvZmZpY2VzIHNob3VsZCBiZSBhZmZvcmRlZCBncmVhdGVyIHByaW1hY3kgaW4gZGljdGF0aW5nIGNsdXN0ZXIgZm9vdHByaW50cyBpbiB0aGVpciByZXNwZWN0aXZlIGFyZWFzLiAgIA0KDQo8YnI+DQoNCiMjIDUuIERlY2lzaW9uIHRyZWVzDQoNCiMjIyA1YS4gSW50cm9kdWN0aW9uIHRvIHRyZWVzIC0tIG9yZ2FzYXRpb25hbCBwcmVzZW5jZQ0KDQpUbyBhaWQgcHJpb3JpdGlzYXRpb24gb2YgcGFycmlzaGVzIC0tIHRoYXQgaXMsIHRvIGRldGVybWluZSB3aGVyZSB3ZSBzaG91bGQgYmUgd29ya2luZyAtLSBpdCBpcyBuZWNlc3NhcnkgdG8gc3BsaXQgdGhlbSB1cCBpbnRvIG1vcmUgZWFzaWx5IGRpZ2VzdGlibGUgZ3JvdXBzIC0tIHdlIHdpbGwgdXNlIGRlY2lzaW9uIHRyZWVzIHRvIGRvIHRoaXMuIEEgcHJpb3JpdGlzYXRpb24gc2NvcmUgaXMgYWxzbyBhbm90aGVyIGNvbW1vbmx5LXVzZWQgcHJpb3JpdGlzYXRpb24gdG9vbCwgYnV0LCBhcyB3ZSB3aWxsIHNlZSwgY29sbGFwc2luZyBhIG51bWJlciBvZiB2YXJpYWJsZXMgZG93biBpbnRvIG9uZSBzY29yZSBpcyBub3QgYWx3YXlzIGhlbHBmdWwuIA0KDQpUbyB1bmRlcnN0YW5kIGhvdyBhIGRlY2lzaW9uIHRyZWUgZnVuY3Rpb25zLCBsZXQgdXMgY29uc3RydWN0IG9uZSB0byBwcmVkaWN0IHdoZXRoZXIgb3Igbm90IHRoZXJlIGlzIGEgaHVtYW5pdGFyaWFuIGFnZW5jeSBwcmVzZW50IGluIGEgcGFycmlzaCAoYG9yZ19wcmVzZW50YCAtLSB0aGlzIGlzIG91ciBkZXBlbmRlbnQgdmFyaWFibGUpLiBXZSBzdXBwbHkgdGhlIG1vZGVsIG91ciBiYXNrZXQgb2YgaW5kaWNhdG9ycyBmcm9tIHdoaWNoIGl0IHdpbGwgY29uc3RydWN0IGEgbW9kZWwgdG8gcHJlZGljdCBvdXIgZGVwZW5kZW50IHZhcmlhYmxlIC0tIHVuaGlkZSB0aGUgY29kZSBiZWxvdyB0byBzZWUgdGhlIGZ1bGwgbW9kZWwgLS0gYnV0IHdlIG1vc3RseSBmZWQgdGhlIG1vZGVsIHRoZSBDZW5zdXMgaW5kaWNhdG9ycy4gVGhlIGRlY2lzaW9uIHRyZWUgcHJpbnRlZCBiZWxvdyBpcyB0aGUgcmVzdWx0OiANCg0KYGBge3IgdHJlZTJ9DQojIGp1c3QgdG8gc2hvdyB0aGUgZGVjaXNpb24gdHJlZSBvZiBob3cgcGFydG5lcnMgc2VlbSB0byBoYXZlIGNob3NlbiBsb2NhdGlvbnMuIA0KIyB1c2luZyBmdWxsIHBhcnIgZGF0YXNldCBmb3IgdGhlIHRyZWUNCiMgbm8gZG91YnQgdGhlcmUgYXJlIG90aGVyIGZhY3RvcnMsIGJ1dCB0aGlzIGlzIHRoZSBkYXRhIEkgaGF2ZSAtLSANCiMgbG9va2luZyBhdCBzcGVjaWZpYyBwYXJ0bmVyIGNoYXJhY3RlcmlzdGljcyB3b3VsZCBiZSBpbnRlcmVzdGluZy4gDQpzZXQuc2VlZCgzMDAwKQ0KDQp0cmVlMiA8LSBwYXJyICU+JSANCiAgcnBhcnQob3JnX3ByZXNlbnQgfiBwZXJjZW50X3BvYnJlICsgcGVyY2VudF91cmJhbmEgKyBkZW5zaWRhZF9wcGxfa20yICsgDQogICAgICAgIHJhem9uX2RlX2RlcGVuZGVuY2lhX2RlX21lbm9yZXNfZGVfMTVfYW5vcyArIHJhem9uX2RlX2RlcGVuZGVuY2lhX3RvdGFsICsgIA0KICAgICAgICBwZXJjZW50X3Npbl9hZ3VhX3NlZ3VyYSArIHBlcmNlbnRfc2luX3NhbmVhbWllbnRvX21lam9yYWRvICsNCiAgICAgICAgcGVyY2VudF9zaW5fc2VydmljaW9fZWxlY3RyaWNvICsgcGVyY2VudF9hbmFsZmFiZXRvICsgcGVyY2VudF9ob2dhcmVzX2plZmF0dXJhX2ZlbWVuaW5hLCANCiAgICAgICAgcHJvbWVkaW9fZGVfcGVyc29uYXNfcG9yX3ZpdmllbmRhLCBkYXRhID0gLiwgbWluYnVja2V0ID0gMTAwKQ0KDQpmYW5jeVJwYXJ0UGxvdCh0cmVlMiwgZGlnaXRzID0gLTMsIHN1YiA9ICIiLCBwYWxldHRlcyA9ICJCbHVlcyIsIHR5cGUgPSAyKQ0KYGBgDQoNClRvIHVuZGVyc3RhbmQgdGhlIHBsb3QgYWJvdmUsIGFsbCBwYXJyaXNoZXMgaGF2ZSBiZWVuIHNwbGl0IGludG8gZm91ciBncm91cHMgKHRoZSB0ZXJtaW5hbCBub2RlcyBhdCB0aGUgYm90dG9tIG1hcmtlZCAqKmA0YCoqLCAqKmA1YCoqLCAqKmA2YCoqIGFuZCAqKmA3YCoqKSBiYXNlZCBvbiB0aGUgcGVyY2VudGFnZSBvZiBwYXJyaXNoZXMgaW4gZWFjaCBub2RlIHdoZXJlIGh1bWFuaXRhcmlhbiBhZ2VuY2llcyBhcmUgcHJlc2VudC4gRWFjaCBidWJibGUgaGFzIHRocmVlIGZpZ3VyZXMgLS0gZm9yIGluc3RhbmNlLCB0aGUgcm9vdCwgYXQgdGhlIHRvcCwgYW5kIG1hcmtlZCBbMV0sIHNob3dzIHRoYXQgb24gYXZlcmFnZSwgMC41MjQgb3IgNTIuNCUgb2YgYWxsIHBhcnJpc2hlcyBoYXZlIGh1bWFuaXRhcmlhbiBhZ2VuY2llcyBwcmVzZW50IGluIHRoZW0uIFRoZSBuZXh0IG51bWJlcnMsICJuID0gMTEwOSIgc2hvd3MgdGhhdCBgciBucm93KHBhcnIpYCBwYXJyaXNoZXMgYXJlIGluIHRoYXQgZ3JvdXAgYW5kIG5leHQgdG8gaXQgaXMgdGhlIHBlcmNlbnRhZ2Ugb2YgcGFycmlzaGVzIGl0IGNvbnRhaW5zLCB3aGljaCwgc2luY2UgaXQgaXMgdGhlIHJvb3QsIGlzIDEwMCUuIA0KDQpXZSBzZWUgdGhhdCAqKmA3YCoqIChpbiBkYXJrIGJsdWUpIHRoZSBub2RlIHdpdGggdGhlIGhpZ2hlc3QgY29uY2VudHJhdGlvbiBvZiBwYXJyaXNoZXMgd2l0aCBhZ2VuY2llcyBwcmVzZW50ICg4Mi44JSksIGNvbnNpc3RzIG9mIHBhcnJpc2hlcyBtb3JlIHRoYW4gNzkuNCUgdXJiYW5pc2VkIGFuZCBkZW5zZXIgdGhhbiAxODcgcHBsL2ttMi4gQW5kICoqYDRgKiosIHRoZSBub2RlIHdpdGggdGhlIGxvd2VzdCBjb25jZW50cmF0aW9uIG9mIHBhcnJpc2hlcyB3aXRoIGFnZW5jaWVzICgyMi42JSkgaXMgbGVzcyB0aGFuIDc5LjQlIHVyYmFuaXNlZCBfYW5kXyBsZXNzIHRoYW4gMjEuOCUgdXJiYW5pc2VkLiANCg0KUGVyaGFwcyBpdCBpcyB1bmRlcnN0YW5kYWJsZSB0aGF0IHRoZSBtb3N0IGhlYXZpbHkgcG9wdWxhdGVkIHBhcnJpc2hlcyBoYXZlIGdyZWF0ZXIgY29uY2VudHJhdGlvbnMgb2Ygb3JnYW5pc2F0aW9ucywgdGhvdWdoIHBvcHVsYXRpb24gZGVuc2l0eSBhbmQgdXJiYW4gcG9wdWxhdGlvbiBhcmUgYm90aCBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBwb3ZlcnR5IGluY2lkZW5jZS4gQW5kIHRoaXMgaXMsIG9mIGNvdXJzZSwgbm90IHRvIGltcGx5IHRoYXQgdGhpcyBhY3R1YWxseSBkZXBpY3RzIHBhcnRuZXJzJyBkZWNpc2lvbi1tYWtpbmcgcHJvY2VzcywganVzdCB0aGF0IHRoZXNlIGFyZSB0aGUgZmFjdG9ycyB0b3dhcmRzIHdoaWNoIHdlLCBhcyBhIHJlc3BvbnNlLCBhcmUgcHJlZGlzcG9zZWQuIA0KDQpUaGUgbGFyZ2VzdCBkZXRlcm1pbmFudHMgb2YgdGhlICpudW1iZXIqIG9mIGJlbmVmaWNpYXJpZXMgcmVhY2hlZCBwZXIgcGFycmlzaCBhcmUgcG9wdWxhdGlvbiBkZW5zaXR5IGFuZCBwZXJjZW50YWdlIHVyYmFuLCBhcyBiZW5lZmljaWFyeSBudW1iZXJzIHRlbmQgdG8gc2NhbGUgaW4gbGluZSB3aXRoIGxhcmdlciBwb3B1bGF0aW9ucy4gDQoNCjxicj4NCg0KIyMjIDViLiBQcmlvcml0aXNhdGlvbiB0cmVlcw0KDQpTZXZlcmFsIHRyZWVzIHdlcmUgYnVpbHQgYW5kIHRyaWFsbGVkIHRvIHNwbGl0IHBhcnJpc2hlcyBpbnRvIHRhcmdldHRpbmcgZ3JvdXBzLiBBcyBtZW50aW9uZWQsIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgY29tZSBmcm9tIGEgcG9vbCBvZiBpbmRpY2F0b3JzIGZyb20gdGhlIGNlbnN1cyBkYXRhc2V0LCB3aXRoIHNvbWUgb3JpZ2luYXRpbmcgZnJvbSB0aGUgMjAxOSBVTklDRUYgTXVuaWNpcGFsIFByaW9yaXRpc2F0aW9uIFRvb2wsIHdoaWNoIHdhcyBhIFByaW5jaXBhbCBDb21wb25lbnRzIEFuYWx5c2lzIG9mIGtleSB2YXJpYWJsZXMgcmVsYXRlZCB0byBwb3ZlcnR5LCBoZWFsdGggYW5kIG1vcnRhbGl0eSBhbmQgdmlvbGVuY2UgYW5kIGluc2VjdXJpdHkuIEFmdGVyIG51bWVyb3VzIGl0ZXJhdGlvbnMsICoqYHRyZWUzYCoqIHdhcyBjaG9zZW4gYW5kIGl0IHNwbGl0cyBwYXJyaXNoZXMgaW50byBncm91cHMgYWNjb3JkaW5nIHRvIHRoZTogIA0KDQoqIFRoZSBwb3ZlcnR5IHNjb3JlLCB3aGljaCBpcyB0aGUgYSByZXNjYWxlZCBhdmVyYWdlIG9mIHRoZSBudW1iZXIgb2YgcG9vciBwZXJzb25zIGFuZCB0aGUgcG92ZXJ0eSBpbmNpZGVuY2Ugb2YgZWFjaCBwYXJyaXNoLiANCiAgDQpUbyBzZWUgdGhlIHNwZWNpZmljIHZhcmlhYmxlcyBhbmQgZm9ybXVsYWUgdXNlZCBmb3IgZWFjaCBvZiB0aGUgbWFqb3IgaXRlcmF0aW9ucywgYXMgd2VsbCBhcyBhZGRpdGlvbmFsIG5vdGVzIG9uIHRoZSBkZXZlbG9wbWVudCBhbmQgYXBwbGljYXRpb24gb2YgZGVjaXNpb24gdHJlZXMsIHVuaGlkZSB0aGUgc291cmNlIGNvZGUgYmVsb3cuIA0KDQpgYGB7ciB0cmVlcy1SRUYtd3JpdGUtaW50by1wYXJyMH0NCiANCiMgQXMgb3Bwb3NlZCB0byBhIHByaW9yaXRpc2F0aW9uIHNjb3JlIC0tIHR5cGljYWxseSB0aGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiBzZXZlcmFsIGRlbW9ncmFwaGljIGFuZCBzb2Npb2Vjb25vbWljIGluZGljYXRvcnMgLS0gYSB0cmVlIGlzIG11Y2ggYmV0dGVyIGF0IGFjY291bnRpbmcgZm9yIHRoZSB2YXJpYXRpb25zIGFjcm9zcyBnZW9ncmFwaGljIGFyZWFzLiBBIHBhcnRuZXIgbWlnaHQgbm90IGhhdmUgdGhlIGNhcGFjaXR5IHRvIHdvcmsgb3V0c2lkZSBvZiB1cmJhbiBhcmVhcyBvciBhbm90aGVyIG1pZ2h0IGhhdmUgc3BlY2lmaWMgZ2VvZ3JhcGhpYyBiaWFzZXMgYW5kIGRlY2lzaW9uIHRyZWVzIGFyZSBhIGdvb2QgdG9vbCB0byBtYWtlIHRoZSBiZXN0IHBvc3NpYmxlIHRhcmdldHRpbmcgZGVjaXNpb25zIHdpdGhpbiBvbmUncyBjb25zdHJhaW50cy4gIA0KDQojIFdpdGggdGhhdCBpbiBtaW5kLCB0cmVlMyB3YXMgZGV2ZWxvcGVkIHRvIGFpZCBmdXR1cmUgcHJpb3JpdGlzYXRpb24uIFRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZSBpdCBzdHJpdmVzIHRvIHByZWRpY3QgaXMgdGhlIHBvdmVydHkgc2NvcmUsIHdoaWNoLCBhcyBtZW50aW9uZWQsIGlzIGp1c3QgdGhlIHJlc2NhbGVkIGF2ZXJhZ2Ugb2YgbnVtYmVyIG9mIHBvb3IgcGVyc29ucyBhbmQgcG92ZXJ0eSBpbmNpZGVuY2UuIFRoZSBwZXJmb3JtYW5jZSBvZiB0cmVlMyB3YXMgY29uc2lkZXJlZCBzdXBlcmlvciB0byBib3RoIHRyZWUxICh3aG9zZSBpbmRlbmRlcGVudCB2YXJpYWJsZSBpcyBqdXN0IHRoZSBhYnNvbHV0ZSBudW1iZXIgb2YgcG9vciBwZXJzb25zKSBhbmQgdHJlZTQgZHVlIHRvIGl0cyBhYmlsaXR5IGNsZWFybHkgZGlzdGluZ3Vpc2ggaXRzIGdyb3VwcyBvZiBwYXJyaXNoZXMgYW5kIGJlY2F1c2UgaXQgaXMgbm90IGRlcGVuZGVudCBvbiBnYXBzIGRhdGEgLS0gbWVhbmluZyBpdCB3aWxsIG5vdCBzaGlmdCB3aGVuIHRoZSA1V3MgYXJlIHVwZGF0ZWQuDQoNCnNldC5zZWVkKDMwMDApDQoNCiMgbnVtYmVyIG9mIG5vdCBjb3ZlcmVkIHBvb3IgcGVyc29ucyANCnRyZWUxIDwtIHBhcnIwICU+JQ0KICBycGFydChub3RfcmVhY2hlZCB+IGVzdGFkbyArIHBlcmNlbnRfcG9icmUgKyBwZXJjZW50X3VyYmFuYSArIA0KICAgICAgICBkZW5zaWRhZF9wcGxfa20yICsgcmF6b25fZGVfZGVwZW5kZW5jaWFfZGVfbWVub3Jlc19kZV8xNV9hbm9zICsgDQogICAgICAgIHJhem9uX2RlX2RlcGVuZGVuY2lhX3RvdGFsICsgIA0KICAgICAgICBwZXJjZW50X3Npbl9hZ3VhX3NlZ3VyYSArIHBlcmNlbnRfc2luX3NhbmVhbWllbnRvX21lam9yYWRvICsNCiAgICAgICAgcGVyY2VudF9zaW5fc2VydmljaW9fZWxlY3RyaWNvICsgcGVyY2VudF9hbmFsZmFiZXRvICsgcGVyY2VudF9ob2dhcmVzX2plZmF0dXJhX2ZlbWVuaW5hLCANCiAgICAgICAgcHJvbWVkaW9fZGVfcGVyc29uYXNfcG9yX3ZpdmllbmRhLCBkYXRhID0gLiwgY3AgPSAwLjAzOCkNCg0KIyB0cmVlIGJhc2VkIG9uIHBvdmVydHlfc2NvcmUNCnRyZWUzIDwtIHBhcnIwICU+JQ0KICBycGFydChwb3ZlcnR5X3Njb3JlIH4gZXN0YWRvICsgcGVyY2VudF91cmJhbmEgKyBkZW5zaWRhZF9wcGxfa20yICsNCiAgICAgICAgcmF6b25fZGVfZGVwZW5kZW5jaWFfZGVfbWVub3Jlc19kZV8xNV9hbm9zICsgcmF6b25fZGVfZGVwZW5kZW5jaWFfdG90YWwgKyAgDQogICAgICAgIHBlcmNlbnRfc2luX2FndWFfc2VndXJhICsgcGVyY2VudF9zaW5fc2FuZWFtaWVudG9fbWVqb3JhZG8gKw0KICAgICAgICBwZXJjZW50X3Npbl9zZXJ2aWNpb19lbGVjdHJpY28gKyBwZXJjZW50X2FuYWxmYWJldG8gKyBwZXJjZW50X2hvZ2FyZXNfamVmYXR1cmFfZmVtZW5pbmEsDQogICAgICAgIHByb21lZGlvX2RlX3BlcnNvbmFzX3Bvcl92aXZpZW5kYSwgZGF0YSA9IC4sIGNwID0gMC4wNDQpDQoNCiMgdHJlZSBiYXNlZCBvbiBnYXAgc2NvcmUgLS0gbGV0J3Mgbm90IHVzZSB0aGlzIGFzIHRyZWUzIGlzIG1vcmUgc3RhYmxlIGFuZCB3aWxsIG5vdCBjaGFuZ2UgYmFzZWQgb24gbmV3IDVXIGRhdGEgDQojIHRyZWU0IDwtIHBhcnIwICU+JQ0KIyAgIHJwYXJ0KGdhcF9zY29yZSB+IGVzdGFkbyArIHBlcmNlbnRfdXJiYW5hICsgZGVuc2lkYWRfcHBsX2ttMiArDQojICAgICAgICAgcmF6b25fZGVfZGVwZW5kZW5jaWFfZGVfbWVub3Jlc19kZV8xNV9hbm9zICsgcmF6b25fZGVfZGVwZW5kZW5jaWFfdG90YWwgKyAgDQojICAgICAgICAgcGVyY2VudF9zaW5fYWd1YV9zZWd1cmEgKyBwZXJjZW50X3Npbl9zYW5lYW1pZW50b19tZWpvcmFkbyArDQojICAgICAgICAgcGVyY2VudF9zaW5fc2VydmljaW9fZWxlY3RyaWNvICsgcGVyY2VudF9hbmFsZmFiZXRvICsgcGVyY2VudF9ob2dhcmVzX2plZmF0dXJhX2ZlbWVuaW5hLCANCiMgICAgICAgICBwcm9tZWRpb19kZV9wZXJzb25hc19wb3Jfdml2aWVuZGEsIGRhdGEgPSAuLCBjcCA9IDAuMDQ1KQ0KDQojIHBsb3RjcCh0cmVlMykNCiMgcHJpbnRjcCh0cmVlMykNCg0KIyBhZGRpbmcgdHJlZTEgYW5kIHRyZWUzIHJ1bGVzIHRvIHRoZSBkYXRhc2V0IA0KcGFycjAgPC0gcGFycjAgJT4lIA0KICBtdXRhdGUocnVsZTEgPSByb3cubmFtZXModHJlZTEkZnJhbWUpW3RyZWUxJHdoZXJlXSkgJT4lDQogICAgICBsZWZ0X2pvaW4ocnBhcnQucnVsZXMudGFibGUodHJlZTEpICU+JSANCiAgICAgIGZpbHRlcihMZWFmID09IFRSVUUpICU+JSANCiAgICAgIHJlbmFtZShydWxlMSA9IFJ1bGUpICU+JSANCiAgICAgIGdyb3VwX2J5KHJ1bGUxKSAlPiUgDQogICAgICBzdW1tYXJpc2Uoc3VicnVsZXMxID0gcGFzdGUoU3VicnVsZSwgY29sbGFwc2UgPSAiLCIpKSkgICU+JSANCiAgbXV0YXRlKHJ1bGUzID0gcm93Lm5hbWVzKHRyZWUzJGZyYW1lKVt0cmVlMyR3aGVyZV0pICU+JQ0KICAgICAgbGVmdF9qb2luKHJwYXJ0LnJ1bGVzLnRhYmxlKHRyZWUzKSAlPiUgDQogICAgICBmaWx0ZXIoTGVhZiA9PSBUUlVFKSAlPiUgDQogICAgICByZW5hbWUocnVsZTMgPSBSdWxlKSAlPiUgDQogICAgICBncm91cF9ieShydWxlMykgJT4lIA0KICAgICAgc3VtbWFyaXNlKHN1YnJ1bGVzMyA9IHBhc3RlKFN1YnJ1bGUsIGNvbGxhcHNlID0gIiwiKSkpDQoNCmBgYA0KDQo8YnI+DQoNCiMjIyA1Yy4gU3ViLWdyb3VwcyBvZiBkZWNpc2lvbiB0cmVlMw0KDQpCZWxvdyBpcyBhIHBsb3Qgb2YgKipgdHJlZTNgKiogLS0gdGhlIGByIG5yb3cocGFycjApYCBwYXJyaXNoZXMgd2hlcmUgdGhlIG51bWJlciBvZiBiZW5lZmljaWFyaWVzIGRvZXMgbm90IGV4Y2VlZCB0aGUgbnVtYmVyIG9mIHBvb3IgcGVyc29ucyAoY29ycmVzcG9uZGluZyB0byB0aGUgX3VuZGVyXyBhbmQgX25vIGNvdmVyYWdlXyBjYXRlZ29yaWVzKSBoYXZlIGJlZW4gc3BsaXQgaW50byBmb3VyIHRlcm1pbmFsIG5vZGVzOiAqKmA0YCoqLCAqKmA1YCoqLCAqKmA2YCoqIGFuZCAqKmA3YCoqLiBUaGUgbWFubmVyIGluIHdoaWNoIHRoZXkgaGF2ZSBiZWVuIHNwbGl0IGlzIG1lYW5pbmdmdWwgZm9yIHRhcmdldHRpbmcgZGVjaXNpb25zIGFuZCB0aGlzIHNlY3Rpb24gd2lsbCBjb21wYXJlIHRoZSBjaGFyYWN0ZXJpc3RpY3Mgb2YgZWFjaC4NCg0KYGBge3IgdHJlZTMtcnBhcnRQbG90fQ0KDQpmYW5jeVJwYXJ0UGxvdCh0cmVlMywgZGlnaXRzID0gLTMsIHN1YiA9ICIiLCBwYWxldHRlcyA9ICJCbHVlcyIsIHR5cGUgPSAyKQ0KYGBgDQogDQo8YnI+DQogDQojIyMjIFN1bW1hcnkgdGFibGUgb2YgdGhlIHRlcm1pbmFsIG5vZGVzIG9mIHRyZWUzIA0KDQpgYGB7ciB0cmVlMy1ydWxlcy1UQUJMRX0NCiAgDQpwYXJyMCAlPiUgDQogIGdyb3VwX2J5KHJ1bGUzKSAlPiUgDQogIHN1bW1hcmlzZShwYXJyX25vX2JlbiA9IG5fZGlzdGluY3QocGNvZGUzW2JlbmVmaWNpYXJpb3MgPT0gMF0pLA0KICAgICAgICAgICAgYmVuZWZpY2lhcmlvcyA9IHN1bShiZW5lZmljaWFyaW9zKSwNCiAgICAgICAgICAgIGF2Z19iZW5lZmljaWFyaW9zID0gc3VtKGJlbmVmaWNpYXJpb3MpIC8gbigpLCANCiAgICAgICAgICAgIG5vdF9yZWFjaGVkID0gc3VtKG5vdF9yZWFjaGVkKSwNCiAgICAgICAgICAgIGF2Z19ub3RfcmVhY2hlZCA9IHN1bShub3RfcmVhY2hlZCkgLyBuKCksDQogICAgICAgICAgICBhdmdfb3JnX2NvdW50ID0gbWVhbihvcmdfY291bnQpLA0KICAgICAgICAgICAgYXZnX3BvYmxhY2lvbiA9IG1lYW4ocG9ibGFjaW9uXzIwMTkpLA0KICAgICAgICAgICAgcGVyY2VudF9wb2JyZSA9IHJvdW5kKHN1bShwb2JfcG9icmUpIC8gc3VtKHBvYmxhY2lvbl8yMDE5KSwgZGlnaXRzID0gMiksDQogICAgICAgICAgICBwZXJjZW50X3VyYmFuYSA9IHJvdW5kKHN1bShwb2JfdXJiYW5hKSAvIHN1bShwb2JsYWNpb25fMjAxOSksIGRpZ2l0cyA9IDIpLA0KICAgICAgICAgICAgZGVuc2lkYWRfcHBsX2ttMiA9IHN1bShwb2JsYWNpb25fMjAxOSkgLyBzdW0oYXJlYV9rbTIsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBwYXJyb3F1aWFzID0gbigpKSAlPiUgDQogIGdhdGhlcihrZXkgPSB2YXJpYWJsZSwgdmFsdWUgPSB2YWx1ZSwgMjpuY29sKC4pKSAlPiUgDQogIHNwcmVhZF8oa2V5ID0gbmFtZXMoLilbMV0sIHZhbHVlID0gJ3ZhbHVlJykgJT4lIA0KICAjIHJlb3JkZXJpbmcgdGhlIHRhYmxlIGluc3RlYWQgb2YgaGF2aW5nIGl0IGJlIGFscGhhYmV0aWNhbA0KICBhcnJhbmdlKGZhY3Rvcih2YXJpYWJsZSwgbGV2ZWxzID0gYygibm90X3JlYWNoZWQiLCAiYXZnX25vdF9yZWFjaGVkIiwgImF2Z19wb2JsYWNpb24iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImJlbmVmaWNpYXJpb3MiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiYXZnX2JlbmVmaWNpYXJpb3MiLCAgImF2Z19vcmdfY291bnQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyY2VudF9wb2JyZSIsICJwZXJjZW50X3VyYmFuYSIsICJkZW5zaWRhZF9wcGxfa20yIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwYXJyb3F1aWFzIiwgInBhcnJfbm9fYmVuIikpKSAlPiUgIA0KICANCiAgcGFuZGVyKGJpZy5tYXJrID0gIiwiKQ0KDQpgYGANCg0KKiAqKmA0YCoqIGNvbnNpc3RzIG9mIHBvcHVsYXRpb24gY2VudHJlcyB3aGljaCBhcmUgZWFzeSB0byByZWFjaCwgYnV0IHdpdGggb25seSAyMS44JSBvZiB0aGUgcG9wdWxhdGlvbiBiZWluZyBwb29yLCBjYXJlZnVsIHRhcmdldHRpbmcgYW5kIGJlbmVmaWNpYXJ5IHNlbGVjdGlvbiBpcyByZXF1aXJlZCAtLSBibGFua2V0IGNvdmVyYWdlIHdpbGwgb25seSByZXN1bHQgaW4gZXhjZXNzaXZlIGluY2x1c2lvbiBlcnJvcnMuIEl0IGFsc28gaGFzIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgbnVtYmVyIG9mIG9yZ2FuaXNhdGlvbnMgcHJlc2VudCBwZXIgcGFycmlzaCAoYXZnX29yZ19jb3VudCkuIFRoZXJlIGFyZSBgciBmaWx0ZXIocGFycjAsIHJ1bGUzID09ICI0IikgJT4lIG5yb3coKWAgcGFycmlzaGVzIGluIHRoaXMgZ3JvdXAuIFRoZXNlIHBhcnJpc2hlcyBzaG91bGQgbm90IGJlIHByaW9yaXRpc2VkIC0tIHJlc291cmNlcyBzaG91bGQgYmUgYWxsb2NhdGVkIGVsc2V3aGVyZS4gDQoNCiogKipgNWAqKiBpcyBwcm9iYWJseSB0aGUgYmVzdCBvcHRpb24gZm9yIGV4cGFuc2lvbiBmb3IgbW9zdCBwYXJ0bmVycyAtLSBpdCBoYXMgdGhlIGhpZ2hlc3QgY29uY2VudHJhdGlvbiBvZiBwb29yIHBlcnNvbnMgbm90IGNvdmVyZWQgcGVyIHBhcnJpc2ggKG5jX3Blcl9wYXJyKSwgaXMgc3Vic3RhbnRpYWxseSBwb29yZXIgdGhhbiAqKmA0YCoqLCB3aXRoIGEgcG92ZXJ0eSBpbmNpZGVuY2Ugb2YgMzglLiBBZGRpdGlvbmFsbHksIHRoZXNlIHBhcnJpc2hlcyBhcmUgc3RpbGwgdmVyeSB1cmJhbmlzZWQgKDkyLjUlKSwgbWVhbmluZyB0aGF0IGFjY2VzcyB0byB0aGVzZSBwb3B1bGF0aW9ucyB3aWxsIG5vdCBiZSBjaGFsbGVuZ2luZy4gVGhlIGNvdmVyYWdlIG9mIG9yZ2FuaXNhdGlvbnMgaXMgc3RpbGwgZmFpcmx5IGhpZ2ggYW5kIHBhcnRuZXJzIHNob3VsZCBjb25zaWRlciBleHBhbmRpbmcgaW50byBwYXJyaXNoZXMgdG8gdGhlIG9uZXMgdGhleSBjdXJyZW50bHkgY292ZXIuIFRoaXMgaXMgdGhlIGxhcmdlc3QgZ3JvdXAsIHdpdGggYHIgZmlsdGVyKHBhcnIwLCBydWxlMyA9PSAiNSIpICU+JSBucm93KClgIHBhcnJpc2hlcy4gDQoNCiogKipgNmAqKiBpcyB3aGVyZSBhY2Nlc3Mgc3RhcnRzIHRvIGdldCBtb3JlIGNoYWxsZW5naW5nIC0tIHRob3VnaCB0aGVzZSBwYXJyaXNoZXMgaGF2ZSBhbiBhdmVyYWdlIHBvdmVydHkgaW5jaWRlbmNlIG9mIDUyJSwgdGhlIHJhdGUgb2YgdXJiYW5pc2F0aW9uIGRyb3BzIHRvIDc1JSBhbmQgdGhlIHBvcHVsYXRpb24gZGVuc2l0eSBpcyBvbmx5IDE4IHBwbC9rbTIuIEJ1dCB0aGVyZSBhcmUgc3RpbGwgbW9yZSBwb29yIHBlcnNvbnMgbm90IGNvdmVyZWQgcGVyIHBhcnJpc2ggaW4gdGhpcyBncm91cCB0aGFuIGluICoqYDRgKiouIFRoZXJlIGFyZSBgciBmaWx0ZXIocGFycjAsIHJ1bGUzID09ICI2IikgJT4lIG5yb3coKWAgcGFycmlzaGVzIGluIHRoaXMgZ3JvdXAuIA0KDQoqICoqYDdgKiogY29uc2lzdHMgb2YgdGhlIHBvb3Jlc3QsIG1vc3QgdnVsbmVyYWJsZSBhbmQgbW9zdCByZW1vdGUgcGFycmlzaGVzLiBXb3JraW5nIGluIHRoZXNlIGFyZWFzIHdpbGwgaW5jdXIgc2lnbmlmaWNhbnQgb3BlcmF0aW9uYWwgYW5kIGxvZ2lzdGljYWwgY29zdHMuIEhvd2V2ZXIsIHdpdGggYW4gYXZlcmFnZSBwb3ZlcnR5IGluY2lkZW5jZSBvZiA3NS4yJSwgYmxhbmtldCBjb3ZlcmFnZSB3aWxsIGJlIHdhcnJhbnRlZCBpbiBtYW55IGNhc2VzIC0tIGlmIHRoZSBjaGFsbGVuZ2Ugb2YgcmVhY2hpbmcgYWxsIG9mIHRoZSBwb3B1bGF0aW9uIGNhbiBiZSBtZXQuIEFkZGl0aW9uYWxseSwgdGhleSBhbHNvIGhhdmUgdGhlIGxvd2VzdCBhdmVyYWdlIG51bWJlciBvZiBwb29yIHBlcnNvbnMgbm90IGNvdmVyZWQsIGdpdmVuIHRoZWlyIGV4dHJlbWVseSBsb3cgcG9wdWxhdGlvbiBkZW5zaXR5IG9mIDEuOCBwcGwva20yLiBIdW1hbml0YXJpYW4gYWdlbmNpZXMgaGF2ZSB0aGUgbG93ZXN0IHByZXNlbmNlIGluIHRoZXNlIHBhcnJpc2hlcy4gSXQgaXMgYWR2aXNhYmxlIGZvciBkb25vcnMgdG8gaW5jZW50aXZpc2UgYWN0aXZpdGllcyBpbiB0aGVzZSBhcmVhcyBhcyBpdCBpcyBjbGVhciB0aGF0IGh1bWFuaXRhcmlhbiBhZ2VuY2llcyBhcmUgYXZvaWRpbmcgdGhlbS4gVGhlcmUgYXJlIGByIGZpbHRlcihwYXJyMCwgcnVsZTMgPT0gIjciKSAlPiUgbnJvdygpYCBwYXJyaXNoZXMgaW4gdGhpcyBncm91cC4NCg0KDQojIyMgNWQuIE1hcHMgb2YgcGFycmlzaGVzIGJ5IGRlY2lzaW9uIHRyZWUgbm9kZQ0KDQpgYGB7ciB0cmVlLTMtTUFQLW9yZy1wcmVzZW50fQ0KIyBqdXN0IG9uZSBub3RlIGZvciB0aGlzIG1hcCAtLSBJIHN0aWxsIGNhbid0IGZpZ3VyZSBvdXQgaG93IHRvIGdldCB0aGUgdG9vbHRpcCB0byBhcHBlYXIgd2hlbg0KIyB5b3UncmUgaG92ZXJpbmcgb3ZlciB0aGUgY2VudHJvaWQgaW5zdGVhZCBvZiBhdCB0aGUgYm9yZGVyOyBob3Zlcm9uIGZpbGwgZG9lc24ndCB3b3JrLiANCiMgSSB0aGluayB5b3Ugc2hvdWxkIGp1c3QgYXNrIHN0YWNrb3ZlcmZsb3cgR0lTDQoNCiMgaGV4IGZvciBTZXQyICIjNjZDMkE1IiwgIiNGQzhENjIiLCAiIzhEQTBDQiIsICIjRTc4QUMzIiwgIiNGRkZGRkYiDQojIGhleCBmb3IgRGFyazIgIiMxQjlFNzciLCAiI0Q5NUYwMiIsICIjNzU3MEIzIiwgIiNFNzI5OEEiLCAiI0ZGRkZGRiINCiMgaGV4IGZvciBBY2NlbnQgIiM3RkM5N0YiLCAiI0JFQUVENCIsICIjRkRDMDg2IiwgIiNGRkZGOTkiLCAiI0ZGRkZGRiINCiMgc2NhbGVfZmlsbF92aXJpZGlzX2QoKQ0KIyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCkpDQoNCnBhcnJtYXBfb3JnIDwtIHBhcnIgJT4lIA0KICBsZWZ0X2pvaW4ocGFycjAgJT4lIA0KICAgICAgICAgICAgICBzZWxlY3QocGNvZGUzLCBydWxlMyksIGJ5ID0gInBjb2RlMyIpICU+JSANCiAgcmlnaHRfam9pbihwY29kZTNfc2hhcGUsIGJ5ID0gInBjb2RlMyIpICU+JSANCiAgc3RfYXNfc2YoKSAlPiUgDQogIG11dGF0ZShub3RfcmVhY2hlZCA9IHJvdW5kKG5vdF9yZWFjaGVkLCBkaWdpdHMgPSAwKSwNCiAgICAgICAgIHRyZWVfbm9kZSA9IHJ1bGUzKSAlPiUgDQogIG11dGF0ZV9hdCh2YXJzKHBlcmNlbnRfcG9icmUsIHBlcmNlbnRfdXJiYW5hKSwgfihyb3VuZCguLCBkaWdpdHMgPSAyKSkpICU+JSANCiAgZ2dwbG90KCkgKw0KICBnZW9tX3NmKHNpemUgPSAwLjEsIA0KICAgICAgICAgIGFlcyhmaWxsID0gdHJlZV9ub2RlLA0KICAgICAgICAgICAgICB0ZXh0ID0gcGFzdGUwKHBhcnJvcXVpYSwiLCIsICJcbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbXVuaWNpcGlvLCAiLCIsICJcbiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBlc3RhZG8sICJcbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIm5vdCBjb3ZlcmVkOiAiLCBub3RfcmVhY2hlZCwgIlxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJwb3ZlcnR5IGluY2lkZW5jZTogIiwgcGVyY2VudF9wb2JyZSwgIlxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50IHVyYmFuOiAiLCBwZXJjZW50X3VyYmFuYSwgIlxuIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJvcmcgcHJlc2VudCA6Iiwgb3JnX3ByZXNlbnQpLA0KICAgICAgICAgICAgIGFscGhhID0gb3JnX3ByZXNlbnQpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM2NkMyQTUiLCAiI0ZDOEQ2MiIsICIjOERBMENCIiwgIiNFNzhBQzMiKSkgKw0KICBzY2FsZV9hbHBoYV9kaXNjcmV0ZShyYW5nZSA9IGMoMSwgMC43KSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSkgKw0KICBndWlkZXMoYWxwaGEgPSBGQUxTRSkgKw0KICBsYWJzKGZpbGwgPSAiVHJlZSBub2RlIiwNCiAgICAgICBhbHBoYSA9ICIiKSArDQogIGdndGl0bGUoJ01hcCBvZiBwYXJyaXNoZXMgYnkgZGVjaXNpb24gdHJlZSBub2RlIChjb2xvdXIpICYgaWYgb3JnYW5pc2F0aW9ucyBwcmVzZW50IChhbHBoYSknKQ0KICANCmdncGxvdGx5KHBhcnJtYXBfb3JnLCB0b29sdGlwID0gYygidGV4dCIsICJmaWxsIikpICU+JQ0KICBsYXlvdXQodGl0bGUgPSBsaXN0KHRleHQgPSBwYXN0ZTAoDQogICAgIk1hcCBvZiBwYXJyaXNoZXMgYnkgZGVjaXNpb24gdHJlZSBub2RlIChjb2xvdXIpICYgaWYgb3JnYW5pc2F0aW9ucyBwcmVzZW50IChhbHBoYSkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxzdXA+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibW91c2Ugb3ZlciBmb3IgZGV0YWlsczsgZHJhZyBhbmQgY2xpY2sgdG8gc2VsZWN0IGFuZCB6b29tOyBkb3VibGUtY2xpY2sgbGVnZW5kIHNlbGVjdC9kZXNlbGVjdCIsIjwvc3VwPiIpKSkNCg0KDQpgYGANCg0KQWJvdmUgaXMgYSBtYXAgb2YgcGFycmlzaGVzIGJ5IHRoZWlyIGRlY2lzaW9uIHRyZWUgbm9kZSAoZGVub3RlZCBieSBjb2xvdXIpLCB3ZSBoYXZlIGFsc28gZGVjcmVhc2VkIHRoZSBhbHBoYSBmb3IgcGFycmlzaGVzIHdoZXJlIHRoZXJlIGFyZSBhbHJlYWR5IG9yZ2FuaXNhdGlvbnMgcHJlc2VudCwgbWVhbmluZyB0aGF0IHRoZXkgYXBwZWFyIG1vcmUgdHJhbnNwYXJlbnQuIExvb2tpbmcgYXQgKipgNGAqKiBhbmQgKipgNWAqKiwgd2UgY2FuIHNlZSB0aGUgcGFycmlzaGVzIHRoYXQgY29uZm9ybSB0byB0aGUgdGhlIFZlbmV6dWVsYSBDb3N0YWwgUmFuZ2UgYW5kIHRoZSBWZW5lenVlbGFuIEFuZGVzLCB3aGVyZSBtb3N0IG9mIHRoZSBjb3VudHJ5J3MgcG9wdWxhdGlvbiBpcyBjb25jZW50cmF0ZWQ7IGFzIGEgcmVtaW5kZXIsIHBhcnJpc2hlcyBpbiBub2RlICoqYDVgKiogYXJlIGV4Y2VsbGVudCBjYW5kaWRhdGVzIGZvciBleHBhbnNpb24uIA0KDQpXZSBhbHNvIHNlZSB0aHJlZSBsYXJnZSBjbHVzdGVycyBvZiBwYXJyaXNoZXMgZnJvbSBub2RlICoqYDdgKiogLS0gdGhlIHBvb3Jlc3QgYW5kIG1vc3Qtc3BhcnNlbHkgcG9wdWxhdGVkIGFyZWFzIC0tIGluIEFtYXpvbmFzIGFuZCBCb2xpdmFyIChhdCB0aGUgYm90dG9tIG9mIHRoZSBtYXApLCBpbiBEZWx0YSBBbWFjdXJvIChhdCB0aGUgZXh0cmVtZSByaWdodCkgYW5kIGluIExhcmEgYW5kIEZhbGNvbiAodG9wLWxlZnQpLiANCg0KKiBBZGRpdGlvbmFsIG5vdGVzIG9uIHRyZWUxLCB3aGljaCB3YXMgbm90IHNlbGVjdGVkIC0tIHVuaGlkZSBjb2RlIHRvIHNlZQ0KDQpgYGB7ciB0cmVlMS1ub3RlcywgcmVzdWx0cz1GQUxTRX0NCiMgdGhlIG1haW4gcHJvYmxlbSBJIHNlZSBpcyB0aGF0IGVhY2ggb2YgdGhlIGxlYXZlcyBoYXMgbGl0dGxlIHZhcmlhbmNlIGluIHRlcm1zIG9mIHBvdmVydHkgaW5jaWRlbmNlDQojIGJ1dCBsZXQgbWUga25vdyBpZiB5b3Ugd2FudCBtYXBzIG9yIHByb2R1Y3RzIGZvY3VzZWQgb24gdGhpcyB0cmVlLCBpdCdzIHByZXR0eSBlYXN5IHRvIGRvLiBbMTVdIGlzIHZlcnksIHZlcnkgYXR0cmFjdGl2ZS4gTWF5YmUgSSBjYW4gDQoNCiMgNiBpcyBkZW5zZSwgdXJiYW4gYW5kIGhpZ2hlc3Qgb3BlcmF0aW9uYWwgcHJlc2VuY2UsDQojIDIgaXMganVzdCB0b28gYmlnLiA4MDAgcGFycmlzaGVzIGlzIGp1c3QgdG9vIG1hbnkuIFRoZSBsb3cgZW5kIGlzIGRpc3Rpbmd1aXNoZWQgbXVjaCBiZXR0ZXIgaW4gdHJlZTMNCiMgMTQgaXMganVzdCByaWNoLCB1cmJhbiBhbmQgbm90IGEgcHJpb3JpdHkuIEl0J3MgYWxzbyBhIHJlYWxseSBzbWFsbCBsZWFmLiAgDQojIDE1IGlzIGFjdHVhbGx5IGEgcmVhbGx5IGdvb2QgbGVhZiAtLSByZWFsbHkgaGlnaCBuY19wZXJfcGFyciwgZmV3IHBhcnJpc2hlcywgdmVyeSBkZW5zZSwgdmVyeSB1cmJhbiBhbmQgNDIlIHBvb3IgYW5kIHN1Y2ggYW4gaW1tZW5zZWx5IGxvdyBjb3ZlcmFnZSBwZXJjZW50LiBHb29kIGxvdy1oYW5naW5nIGZydWl0LiBJIGFsbW9zdCB3YW50IHRvIGtlZXAgdHJlZTEganVzdCBiZWNhdXNlIG9mIHRoaXMgbGVhZi4gTWF5YmUgSSB3aWxsIG1ha2Ugb25lIG1hcCBqdXN0IGZvciB0aGlzLiA1OSw1MDggbmNfcGVyX3BhcnIgaXMgbWFzc2l2ZS4gDQoNCnBhcnIwICU+JSANCiAgZ3JvdXBfYnkocnVsZTEpICU+JSANCiAgc3VtbWFyaXNlKHBhcnJfbm9fYmVuID0gbl9kaXN0aW5jdChwY29kZTNbYmVuZWZpY2lhcmlvcyA9PSAwXSksIA0KICAgICAgICAgICAgYmVuZWZpY2lhcmlvcyA9IHN1bShiZW5lZmljaWFyaW9zKSwNCiAgICAgICAgICAgIGJlbl9wZXJfcGFyciA9IHN1bShiZW5lZmljaWFyaW9zKSAvIG4oKSwgDQogICAgICAgICAgICBub3RfcmVhY2hlZCA9IHN1bShub3RfcmVhY2hlZCksDQogICAgICAgICAgICBucl9wZXJfcGFyciA9IHN1bShub3RfcmVhY2hlZCkgLyBuKCksDQogICAgICAgICAgICBuY19wZXJfbXVuID0gc3VtKG5vdF9yZWFjaGVkKSAvIG5fZGlzdGluY3QocGNvZGUyKSwgDQogICAgICAgICAgICBhdmdfb3JnX2NvdW50ID0gbWVhbihvcmdfY291bnQpLA0KICAgICAgICAgICAgY292ZXJhZ2VfcGVyY2VudCA9IHN1bShiZW5lZmljaWFyaW9zKSAvIHN1bShwb2JsYWNpb25fMjAxOSksDQogICAgICAgICAgICBwZXJjZW50X3BvYnJlID0gc3VtKHBvYl9wb2JyZSkgLyBzdW0ocG9ibGFjaW9uXzIwMTkpLA0KICAgICAgICAgICAgcGVyY2VudF91cmJhbmEgPSBzdW0ocG9iX3VyYmFuYSkgLyBzdW0ocG9ibGFjaW9uXzIwMTkpLA0KICAgICAgICAgICAgZGVuc2lkYWRfcHBsX2ttMiA9IHN1bShwb2JsYWNpb25fMjAxOSkgLyBzdW0oYXJlYV9rbTIsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBwYXJyb3F1aWFzID0gbigpLA0KICAgICAgICAgICAgbXVuaWNpcGlvcyA9IG5fZGlzdGluY3QocGNvZGUyKSwNCiAgICAgICAgICAgIHBhcnJfcGVyX211biA9IG4oKSAvIG5fZGlzdGluY3QocGNvZGUyKSkgJT4lIA0KICBnYXRoZXIoa2V5ID0gdmFyaWFibGUsIHZhbHVlID0gdmFsdWUsIDI6bmNvbCguKSkgJT4lIA0KICBzcHJlYWRfKGtleSA9IG5hbWVzKC4pWzFdLCB2YWx1ZSA9ICd2YWx1ZScpICU+JSANCiAgYXJyYW5nZShmYWN0b3IodmFyaWFibGUsIGxldmVscyA9IGMoIm5vdF9yZWFjaGVkIiwgIm5yX3Blcl9wYXJyIiwgIm5jX3Blcl9tdW4iLCAiYmVuZWZpY2lhcmlvcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiZW5fcGVyX3BhcnIiLCAgImF2Z19vcmdfY291bnQiLCAiY292ZXJhZ2VfcGVyY2VudCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50X3BvYnJlIiwgInBlcmNlbnRfdXJiYW5hIiwgImRlbnNpZGFkX3BwbF9rbTIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBhcnJvcXVpYXMiLCAicGFycl9ub19iZW4iLCAibXVuaWNpcGlvcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGFycl9wZXJfbXVuIikpKSAlPiUgIHBhbmRlcihiaWcubWFyayA9ICIsIikNCg0KYGBgDQoNCg0KPGJyPjxicj4NCg0KDQojIyA2LiBSZWZlcmVuY2UgVGFibGUgDQpfdHlwZSBvciB1c2Ugc2xpZGVyIHRvIGZpbHRlciBieSBjYXRlZ29yaWVzIG9yIHZhbHVlc18NCg0KYGBge3J9DQpwYXJyMCAlPiUNCiAgc2VsZWN0KC1wZXJjZW50X3RvdGFsX2JlbikgJT4lIA0KICBtdXRhdGUoc2VjdG9yX2NvdW50ID0gcm93U3VtcyhzZWxlY3QoLiwgZW5kc193aXRoKCJfYmVuIikpIT0wKSkgJT4lIA0KICBtdXRhdGUoZWR1Y2FjaW9uX29ubHkgPSBpZmVsc2UoZWR1Y2FjaW9uX2JlbiA+IDAsICJlZHVjYWNpb24iLCAiIiksDQogICAgICAgICBudXRyaWNpb25fb25seSA9IGlmZWxzZShudXRyaWNpb25fYmVuID4gMCwgIm51dHJpY2lvbiIsICIiKSwNCiAgICAgICAgIHNhbHVkX29ubHkgPSBpZmVsc2Uoc2FsdWRfYmVuID4gMCwgInNhbHVkIiwgICIiKSwNCiAgICAgICAgIHdhc2hfb25seSA9IGlmZWxzZSh3YXNoX2JlbiA+IDAsICJ3YXNoIiwgIiIpLA0KICAgICAgICAgcHJvdGVjY2lvbl9vbmx5ID0gaWZlbHNlKHByb3RlY2Npb25fYmVuID4gMCwgInByb3RlY2Npb24iLCAiIiksDQogICAgICAgICBzZWN0b3JzX3ByZXNlbnQgPSBzdHJfdHJpbShwYXN0ZTAoZWR1Y2FjaW9uX29ubHksICIgIiwgbnV0cmljaW9uX29ubHksICIgIiwgcHJvdGVjY2lvbl9vbmx5LCAiICIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhbHVkX29ubHksICIgIiwgd2FzaF9vbmx5KSkpICU+JSANCiAgbXV0YXRlX2F0KHZhcnMocG9iX3BvYnJlLCBub3RfcmVhY2hlZCwgb3JnX2NvdW50KSwgfihyb3VuZCguLCBkaWdpdHMgPSAwKSkpICU+JSANCiAgbXV0YXRlX2F0KHZhcnMocGVyY2VudF9wb2JyZSwgcGVyY2VudF91cmJhbmEpLCB+KHJvdW5kKC4sIGRpZ2l0cyA9IDIpKSkgJT4lIA0KICBzZWxlY3QoZXN0YWRvLCBtdW5pY2lwaW8sIHBhcnJvcXVpYSwgIA0KICAgICAgICAgcGVyY2VudF9wb2JyZSwgcGVyY2VudF91cmJhbmEsIG5vdF9yZWFjaGVkLCBiZW5lZmljaWFyaW9zLCB0cmVlX25vZGUgPSBydWxlMywNCiAgICAgICAgIG9yZ19jb3VudCwgc2VjdG9yX2NvdW50LCBzZWN0b3JzX3ByZXNlbnQsIHBjb2RlMykgJT4lIA0KICBhcnJhbmdlKGRlc2Mobm90X3JlYWNoZWQpKSAlPiUgDQogICMgdGhlIGpzIGlzIGFkanVzdGluZyB0aGUgZm9udCBzaXplIGZvciB0aGUgd2hvbGUgY29udGFpbmVyIC0tIHRoZXJlIGRvZXNuJ3Qgc2VlbSB0byBiZSBhbm90aGVyIHdheQ0KICBkYXRhdGFibGUoZmlsdGVyID0gInRvcCIsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCwgc2Nyb2xsWCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5pdENvbXBsZXRlID0gaHRtbHdpZGdldHM6OkpTKA0KICAgICAgICAgICJmdW5jdGlvbihzZXR0aW5ncywganNvbikgeyIsDQogICAgICAgICAgcGFzdGUwKCIkKHRoaXMuYXBpKCkudGFibGUoKS5jb250YWluZXIoKSkuY3NzKHsnZm9udC1zaXplJzogJyIsICI4LjVwdCIsICInfSk7IiksDQogICAgICAgICAgIn0iKQ0KICAgICAgICkgDQogICAgICkgDQpgYGANCg==